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 166eedbb5bSMichael 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, 1185e6aceb2SRichard Henderson .fields = (const 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 216139fdb3eSNinad Palsule /* Send data to TPM */ 217139fdb3eSNinad Palsule static inline void tpm_tis_i2c_tpm_send(TPMStateI2C *i2cst) 218139fdb3eSNinad Palsule { 219139fdb3eSNinad Palsule uint32_t data; 220139fdb3eSNinad Palsule size_t offset = 0; 221139fdb3eSNinad Palsule uint32_t sz = 4; 222139fdb3eSNinad Palsule 223139fdb3eSNinad Palsule if ((i2cst->operation == OP_SEND) && (i2cst->offset > 1)) { 224139fdb3eSNinad Palsule 225139fdb3eSNinad Palsule switch (i2cst->data[0]) { 226139fdb3eSNinad Palsule case TPM_I2C_REG_DATA_CSUM_ENABLE: 227139fdb3eSNinad Palsule /* 228139fdb3eSNinad Palsule * Checksum is not handled by TIS code hence we will consume the 229139fdb3eSNinad Palsule * register here. 230139fdb3eSNinad Palsule */ 231139fdb3eSNinad Palsule i2cst->csum_enable = i2cst->data[1] & TPM_DATA_CSUM_ENABLED; 232139fdb3eSNinad Palsule break; 233139fdb3eSNinad Palsule case TPM_I2C_REG_DATA_FIFO: 234139fdb3eSNinad Palsule /* Handled in the main i2c_send function */ 235139fdb3eSNinad Palsule break; 236139fdb3eSNinad Palsule case TPM_I2C_REG_LOC_SEL: 237139fdb3eSNinad Palsule /* 238139fdb3eSNinad Palsule * This register is not handled by TIS so save the locality 239139fdb3eSNinad Palsule * locally 240139fdb3eSNinad Palsule */ 241139fdb3eSNinad Palsule if (TPM_TIS_I2C_IS_VALID_LOCTY(i2cst->data[1])) { 242139fdb3eSNinad Palsule i2cst->loc_sel = i2cst->data[1]; 243139fdb3eSNinad Palsule } 244139fdb3eSNinad Palsule break; 245139fdb3eSNinad Palsule default: 246139fdb3eSNinad Palsule /* We handle non-FIFO here */ 247139fdb3eSNinad Palsule 248139fdb3eSNinad Palsule /* Index 0 is a register. Convert byte stream to uint32_t */ 249139fdb3eSNinad Palsule data = i2cst->data[1]; 250139fdb3eSNinad Palsule data |= i2cst->data[2] << 8; 251139fdb3eSNinad Palsule data |= i2cst->data[3] << 16; 252139fdb3eSNinad Palsule data |= i2cst->data[4] << 24; 253139fdb3eSNinad Palsule 254139fdb3eSNinad Palsule /* Add register specific masking */ 255139fdb3eSNinad Palsule switch (i2cst->data[0]) { 256139fdb3eSNinad Palsule case TPM_I2C_REG_INT_ENABLE: 257139fdb3eSNinad Palsule data &= TPM_I2C_INT_ENABLE_MASK; 258139fdb3eSNinad Palsule break; 259139fdb3eSNinad Palsule case TPM_I2C_REG_STS ... TPM_I2C_REG_STS + 3: 260139fdb3eSNinad Palsule /* 261139fdb3eSNinad Palsule * STS register has 4 bytes data. 262139fdb3eSNinad Palsule * As per the specs following writes must be allowed. 263139fdb3eSNinad Palsule * - From base address 1 to 4 bytes are allowed. 264139fdb3eSNinad Palsule * - Single byte write to first or last byte must 265139fdb3eSNinad Palsule * be allowed. 266139fdb3eSNinad Palsule */ 267139fdb3eSNinad Palsule offset = i2cst->data[0] - TPM_I2C_REG_STS; 268139fdb3eSNinad Palsule if (offset > 0) { 269139fdb3eSNinad Palsule sz = 1; 270139fdb3eSNinad Palsule } 271139fdb3eSNinad Palsule data &= (TPM_I2C_STS_WRITE_MASK >> (offset * 8)); 272139fdb3eSNinad Palsule break; 273139fdb3eSNinad Palsule } 274139fdb3eSNinad Palsule 275139fdb3eSNinad Palsule tpm_tis_write_data(&i2cst->state, i2cst->tis_addr + offset, data, 276139fdb3eSNinad Palsule sz); 277139fdb3eSNinad Palsule break; 278139fdb3eSNinad Palsule } 279139fdb3eSNinad Palsule 280139fdb3eSNinad Palsule tpm_tis_i2c_clear_data(i2cst); 281139fdb3eSNinad Palsule } 282139fdb3eSNinad Palsule } 283139fdb3eSNinad Palsule 284139fdb3eSNinad Palsule /* Callback from TPM to indicate that response is copied */ 285139fdb3eSNinad Palsule static void tpm_tis_i2c_request_completed(TPMIf *ti, int ret) 286139fdb3eSNinad Palsule { 287139fdb3eSNinad Palsule TPMStateI2C *i2cst = TPM_TIS_I2C(ti); 288139fdb3eSNinad Palsule TPMState *s = &i2cst->state; 289139fdb3eSNinad Palsule 290139fdb3eSNinad Palsule /* Inform the common code. */ 291139fdb3eSNinad Palsule tpm_tis_request_completed(s, ret); 292139fdb3eSNinad Palsule } 293139fdb3eSNinad Palsule 294139fdb3eSNinad Palsule static enum TPMVersion tpm_tis_i2c_get_tpm_version(TPMIf *ti) 295139fdb3eSNinad Palsule { 296139fdb3eSNinad Palsule TPMStateI2C *i2cst = TPM_TIS_I2C(ti); 297139fdb3eSNinad Palsule TPMState *s = &i2cst->state; 298139fdb3eSNinad Palsule 299139fdb3eSNinad Palsule return tpm_tis_get_tpm_version(s); 300139fdb3eSNinad Palsule } 301139fdb3eSNinad Palsule 302139fdb3eSNinad Palsule static int tpm_tis_i2c_event(I2CSlave *i2c, enum i2c_event event) 303139fdb3eSNinad Palsule { 304139fdb3eSNinad Palsule TPMStateI2C *i2cst = TPM_TIS_I2C(i2c); 305139fdb3eSNinad Palsule int ret = 0; 306139fdb3eSNinad Palsule 307139fdb3eSNinad Palsule switch (event) { 308139fdb3eSNinad Palsule case I2C_START_RECV: 309139fdb3eSNinad Palsule trace_tpm_tis_i2c_event("START_RECV"); 310139fdb3eSNinad Palsule break; 311139fdb3eSNinad Palsule case I2C_START_SEND: 312139fdb3eSNinad Palsule trace_tpm_tis_i2c_event("START_SEND"); 313139fdb3eSNinad Palsule tpm_tis_i2c_clear_data(i2cst); 314139fdb3eSNinad Palsule break; 315139fdb3eSNinad Palsule case I2C_FINISH: 316139fdb3eSNinad Palsule trace_tpm_tis_i2c_event("FINISH"); 317139fdb3eSNinad Palsule if (i2cst->operation == OP_SEND) { 318139fdb3eSNinad Palsule tpm_tis_i2c_tpm_send(i2cst); 319139fdb3eSNinad Palsule } else { 320139fdb3eSNinad Palsule tpm_tis_i2c_clear_data(i2cst); 321139fdb3eSNinad Palsule } 322139fdb3eSNinad Palsule break; 323139fdb3eSNinad Palsule default: 324139fdb3eSNinad Palsule break; 325139fdb3eSNinad Palsule } 326139fdb3eSNinad Palsule 327139fdb3eSNinad Palsule return ret; 328139fdb3eSNinad Palsule } 329139fdb3eSNinad Palsule 330139fdb3eSNinad Palsule /* 331139fdb3eSNinad Palsule * If data is for FIFO then it is received from tpm_tis_common buffer 332139fdb3eSNinad Palsule * otherwise it will be handled using single call to common code and 333139fdb3eSNinad Palsule * cached in the local buffer. 334139fdb3eSNinad Palsule */ 335139fdb3eSNinad Palsule static uint8_t tpm_tis_i2c_recv(I2CSlave *i2c) 336139fdb3eSNinad Palsule { 337139fdb3eSNinad Palsule int ret = 0; 338139fdb3eSNinad Palsule uint32_t data_read; 339139fdb3eSNinad Palsule TPMStateI2C *i2cst = TPM_TIS_I2C(i2c); 340139fdb3eSNinad Palsule TPMState *s = &i2cst->state; 341139fdb3eSNinad Palsule uint16_t i2c_reg = i2cst->data[0]; 342139fdb3eSNinad Palsule size_t offset; 343139fdb3eSNinad Palsule 344139fdb3eSNinad Palsule if (i2cst->operation == OP_RECV) { 345139fdb3eSNinad Palsule 346139fdb3eSNinad Palsule /* Do not cache FIFO data. */ 347139fdb3eSNinad Palsule if (i2cst->data[0] == TPM_I2C_REG_DATA_FIFO) { 348139fdb3eSNinad Palsule data_read = tpm_tis_read_data(s, i2cst->tis_addr, 1); 349139fdb3eSNinad Palsule ret = (data_read & 0xff); 350139fdb3eSNinad Palsule } else if (i2cst->offset < sizeof(i2cst->data)) { 351139fdb3eSNinad Palsule ret = i2cst->data[i2cst->offset++]; 352139fdb3eSNinad Palsule } 353139fdb3eSNinad Palsule 354139fdb3eSNinad Palsule } else if ((i2cst->operation == OP_SEND) && (i2cst->offset < 2)) { 355139fdb3eSNinad Palsule /* First receive call after send */ 356139fdb3eSNinad Palsule 357139fdb3eSNinad Palsule i2cst->operation = OP_RECV; 358139fdb3eSNinad Palsule 359139fdb3eSNinad Palsule switch (i2c_reg) { 360139fdb3eSNinad Palsule case TPM_I2C_REG_LOC_SEL: 361139fdb3eSNinad Palsule /* Location selection register is managed by i2c */ 362139fdb3eSNinad Palsule tpm_tis_i2c_set_data(i2cst, i2cst->loc_sel); 363139fdb3eSNinad Palsule break; 364139fdb3eSNinad Palsule case TPM_I2C_REG_DATA_FIFO: 365139fdb3eSNinad Palsule /* FIFO data is directly read from TPM TIS */ 366139fdb3eSNinad Palsule data_read = tpm_tis_read_data(s, i2cst->tis_addr, 1); 367139fdb3eSNinad Palsule tpm_tis_i2c_set_data(i2cst, (data_read & 0xff)); 368139fdb3eSNinad Palsule break; 369139fdb3eSNinad Palsule case TPM_I2C_REG_DATA_CSUM_ENABLE: 370139fdb3eSNinad Palsule tpm_tis_i2c_set_data(i2cst, i2cst->csum_enable); 371139fdb3eSNinad Palsule break; 372139fdb3eSNinad Palsule case TPM_I2C_REG_INT_CAPABILITY: 373139fdb3eSNinad Palsule /* 374139fdb3eSNinad Palsule * Interrupt is not supported in the linux kernel hence we cannot 375139fdb3eSNinad Palsule * test this model with interrupts. 376139fdb3eSNinad Palsule */ 377139fdb3eSNinad Palsule tpm_tis_i2c_set_data(i2cst, TPM_I2C_INT_ENABLE_MASK); 378139fdb3eSNinad Palsule break; 379139fdb3eSNinad Palsule case TPM_I2C_REG_DATA_CSUM_GET: 380139fdb3eSNinad Palsule /* 381139fdb3eSNinad Palsule * Checksum registers are not supported by common code hence 382139fdb3eSNinad Palsule * call a common code to get the checksum. 383139fdb3eSNinad Palsule */ 384139fdb3eSNinad Palsule data_read = tpm_tis_get_checksum(s); 385139fdb3eSNinad Palsule 386139fdb3eSNinad Palsule /* Save the byte stream in data field */ 387139fdb3eSNinad Palsule tpm_tis_i2c_set_data(i2cst, data_read); 388139fdb3eSNinad Palsule break; 389139fdb3eSNinad Palsule default: 390139fdb3eSNinad Palsule data_read = tpm_tis_read_data(s, i2cst->tis_addr, 4); 391139fdb3eSNinad Palsule 392139fdb3eSNinad Palsule switch (i2c_reg) { 393139fdb3eSNinad Palsule case TPM_I2C_REG_INTF_CAPABILITY: 394139fdb3eSNinad Palsule /* Prepare the capabilities as per I2C interface */ 395139fdb3eSNinad Palsule data_read = tpm_tis_i2c_interface_capability(i2cst, 396139fdb3eSNinad Palsule data_read); 397139fdb3eSNinad Palsule break; 398139fdb3eSNinad Palsule case TPM_I2C_REG_STS ... TPM_I2C_REG_STS + 3: 399139fdb3eSNinad Palsule offset = i2c_reg - TPM_I2C_REG_STS; 400139fdb3eSNinad Palsule /* 401139fdb3eSNinad Palsule * As per specs, STS bit 31:26 are reserved and must 402139fdb3eSNinad Palsule * be set to 0 403139fdb3eSNinad Palsule */ 404139fdb3eSNinad Palsule data_read &= TPM_I2C_STS_READ_MASK; 405139fdb3eSNinad Palsule /* 406139fdb3eSNinad Palsule * STS register has 4 bytes data. 407139fdb3eSNinad Palsule * As per the specs following reads must be allowed. 408139fdb3eSNinad Palsule * - From base address 1 to 4 bytes are allowed. 409139fdb3eSNinad Palsule * - Last byte must be allowed to read as a single byte 410139fdb3eSNinad Palsule * - Second and third byte must be allowed to read as two 411139fdb3eSNinad Palsule * two bytes. 412139fdb3eSNinad Palsule */ 413139fdb3eSNinad Palsule data_read >>= (offset * 8); 414139fdb3eSNinad Palsule break; 415139fdb3eSNinad Palsule } 416139fdb3eSNinad Palsule 417139fdb3eSNinad Palsule /* Save byte stream in data[] */ 418139fdb3eSNinad Palsule tpm_tis_i2c_set_data(i2cst, data_read); 419139fdb3eSNinad Palsule break; 420139fdb3eSNinad Palsule } 421139fdb3eSNinad Palsule 422139fdb3eSNinad Palsule /* Return first byte with this call */ 423139fdb3eSNinad Palsule i2cst->offset = 1; /* keep the register value intact for debug */ 424139fdb3eSNinad Palsule ret = i2cst->data[i2cst->offset++]; 425139fdb3eSNinad Palsule } else { 426139fdb3eSNinad Palsule i2cst->operation = OP_RECV; 427139fdb3eSNinad Palsule } 428139fdb3eSNinad Palsule 429139fdb3eSNinad Palsule trace_tpm_tis_i2c_recv(ret); 430139fdb3eSNinad Palsule 431139fdb3eSNinad Palsule return ret; 432139fdb3eSNinad Palsule } 433139fdb3eSNinad Palsule 434139fdb3eSNinad Palsule /* 435139fdb3eSNinad Palsule * Send function only remembers data in the buffer and then calls 436139fdb3eSNinad Palsule * TPM TIS common code during FINISH event. 437139fdb3eSNinad Palsule */ 438139fdb3eSNinad Palsule static int tpm_tis_i2c_send(I2CSlave *i2c, uint8_t data) 439139fdb3eSNinad Palsule { 440139fdb3eSNinad Palsule TPMStateI2C *i2cst = TPM_TIS_I2C(i2c); 441139fdb3eSNinad Palsule 442139fdb3eSNinad Palsule /* Reject non-supported registers. */ 443139fdb3eSNinad Palsule if (i2cst->offset == 0) { 444139fdb3eSNinad Palsule /* Convert I2C register to TIS register */ 445139fdb3eSNinad Palsule tpm_tis_i2c_to_tis_reg(i2cst, data); 446139fdb3eSNinad Palsule if (i2cst->tis_addr == 0xffffffff) { 447139fdb3eSNinad Palsule return 0xffffffff; 448139fdb3eSNinad Palsule } 449139fdb3eSNinad Palsule 450139fdb3eSNinad Palsule trace_tpm_tis_i2c_send_reg(i2cst->reg_name, data); 451139fdb3eSNinad Palsule 452139fdb3eSNinad Palsule /* We do not support device address change */ 453139fdb3eSNinad Palsule if (data == TPM_I2C_REG_I2C_DEV_ADDRESS) { 454139fdb3eSNinad Palsule qemu_log_mask(LOG_UNIMP, "%s: Device address change " 455139fdb3eSNinad Palsule "is not supported.\n", __func__); 456139fdb3eSNinad Palsule return 0xffffffff; 457139fdb3eSNinad Palsule } 458139fdb3eSNinad Palsule } else { 459139fdb3eSNinad Palsule trace_tpm_tis_i2c_send(data); 460139fdb3eSNinad Palsule } 461139fdb3eSNinad Palsule 462139fdb3eSNinad Palsule if (i2cst->offset < sizeof(i2cst->data)) { 463139fdb3eSNinad Palsule i2cst->operation = OP_SEND; 464139fdb3eSNinad Palsule 465139fdb3eSNinad Palsule /* 466139fdb3eSNinad Palsule * In two cases, we save values in the local buffer. 467139fdb3eSNinad Palsule * 1) The first value is always a register. 468139fdb3eSNinad Palsule * 2) In case of non-FIFO multibyte registers, TIS expects full 469139fdb3eSNinad Palsule * register value hence I2C layer cache the register value and send 470139fdb3eSNinad Palsule * to TIS during FINISH event. 471139fdb3eSNinad Palsule */ 472139fdb3eSNinad Palsule if ((i2cst->offset == 0) || 473139fdb3eSNinad Palsule (i2cst->data[0] != TPM_I2C_REG_DATA_FIFO)) { 474139fdb3eSNinad Palsule i2cst->data[i2cst->offset++] = data; 475139fdb3eSNinad Palsule } else { 476139fdb3eSNinad Palsule /* 477139fdb3eSNinad Palsule * The TIS can process FIFO data one byte at a time hence the FIFO 478139fdb3eSNinad Palsule * data is sent to TIS directly. 479139fdb3eSNinad Palsule */ 480139fdb3eSNinad Palsule tpm_tis_write_data(&i2cst->state, i2cst->tis_addr, data, 1); 481139fdb3eSNinad Palsule } 482139fdb3eSNinad Palsule 483139fdb3eSNinad Palsule return 0; 484139fdb3eSNinad Palsule } 485139fdb3eSNinad Palsule 486139fdb3eSNinad Palsule /* Return non-zero to indicate NAK */ 487139fdb3eSNinad Palsule return 1; 488139fdb3eSNinad Palsule } 489139fdb3eSNinad Palsule 4903885fa15SRichard Henderson static const Property tpm_tis_i2c_properties[] = { 491139fdb3eSNinad Palsule DEFINE_PROP_TPMBE("tpmdev", TPMStateI2C, state.be_driver), 492139fdb3eSNinad Palsule }; 493139fdb3eSNinad Palsule 494139fdb3eSNinad Palsule static void tpm_tis_i2c_realizefn(DeviceState *dev, Error **errp) 495139fdb3eSNinad Palsule { 496139fdb3eSNinad Palsule TPMStateI2C *i2cst = TPM_TIS_I2C(dev); 497139fdb3eSNinad Palsule TPMState *s = &i2cst->state; 498139fdb3eSNinad Palsule 499139fdb3eSNinad Palsule if (!tpm_find()) { 500139fdb3eSNinad Palsule error_setg(errp, "at most one TPM device is permitted"); 501139fdb3eSNinad Palsule return; 502139fdb3eSNinad Palsule } 503139fdb3eSNinad Palsule 504139fdb3eSNinad Palsule /* 5056eedbb5bSMichael Tokarev * Get the backend pointer. It is not initialized properly during 506139fdb3eSNinad Palsule * device_class_set_props 507139fdb3eSNinad Palsule */ 508139fdb3eSNinad Palsule s->be_driver = qemu_find_tpm_be("tpm0"); 509139fdb3eSNinad Palsule 510139fdb3eSNinad Palsule if (!s->be_driver) { 511139fdb3eSNinad Palsule error_setg(errp, "'tpmdev' property is required"); 512139fdb3eSNinad Palsule return; 513139fdb3eSNinad Palsule } 514139fdb3eSNinad Palsule } 515139fdb3eSNinad Palsule 516139fdb3eSNinad Palsule static void tpm_tis_i2c_reset(DeviceState *dev) 517139fdb3eSNinad Palsule { 518139fdb3eSNinad Palsule TPMStateI2C *i2cst = TPM_TIS_I2C(dev); 519139fdb3eSNinad Palsule TPMState *s = &i2cst->state; 520139fdb3eSNinad Palsule 521139fdb3eSNinad Palsule tpm_tis_i2c_clear_data(i2cst); 522139fdb3eSNinad Palsule 523139fdb3eSNinad Palsule i2cst->csum_enable = 0; 524139fdb3eSNinad Palsule i2cst->loc_sel = 0x00; 525139fdb3eSNinad Palsule 526139fdb3eSNinad Palsule return tpm_tis_reset(s); 527139fdb3eSNinad Palsule } 528139fdb3eSNinad Palsule 529*12d1a768SPhilippe Mathieu-Daudé static void tpm_tis_i2c_class_init(ObjectClass *klass, const void *data) 530139fdb3eSNinad Palsule { 531139fdb3eSNinad Palsule DeviceClass *dc = DEVICE_CLASS(klass); 532139fdb3eSNinad Palsule I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); 533139fdb3eSNinad Palsule TPMIfClass *tc = TPM_IF_CLASS(klass); 534139fdb3eSNinad Palsule 535139fdb3eSNinad Palsule dc->realize = tpm_tis_i2c_realizefn; 536e3d08143SPeter Maydell device_class_set_legacy_reset(dc, tpm_tis_i2c_reset); 537139fdb3eSNinad Palsule dc->vmsd = &vmstate_tpm_tis_i2c; 538139fdb3eSNinad Palsule device_class_set_props(dc, tpm_tis_i2c_properties); 539139fdb3eSNinad Palsule set_bit(DEVICE_CATEGORY_MISC, dc->categories); 540139fdb3eSNinad Palsule 541139fdb3eSNinad Palsule k->event = tpm_tis_i2c_event; 542139fdb3eSNinad Palsule k->recv = tpm_tis_i2c_recv; 543139fdb3eSNinad Palsule k->send = tpm_tis_i2c_send; 544139fdb3eSNinad Palsule 545139fdb3eSNinad Palsule tc->model = TPM_MODEL_TPM_TIS; 546139fdb3eSNinad Palsule tc->request_completed = tpm_tis_i2c_request_completed; 547139fdb3eSNinad Palsule tc->get_version = tpm_tis_i2c_get_tpm_version; 548139fdb3eSNinad Palsule } 549139fdb3eSNinad Palsule 550139fdb3eSNinad Palsule static const TypeInfo tpm_tis_i2c_info = { 551139fdb3eSNinad Palsule .name = TYPE_TPM_TIS_I2C, 552139fdb3eSNinad Palsule .parent = TYPE_I2C_SLAVE, 553139fdb3eSNinad Palsule .instance_size = sizeof(TPMStateI2C), 554139fdb3eSNinad Palsule .class_init = tpm_tis_i2c_class_init, 555139fdb3eSNinad Palsule .interfaces = (InterfaceInfo[]) { 556139fdb3eSNinad Palsule { TYPE_TPM_IF }, 557139fdb3eSNinad Palsule { } 558139fdb3eSNinad Palsule } 559139fdb3eSNinad Palsule }; 560139fdb3eSNinad Palsule 561139fdb3eSNinad Palsule static void tpm_tis_i2c_register_types(void) 562139fdb3eSNinad Palsule { 563139fdb3eSNinad Palsule type_register_static(&tpm_tis_i2c_info); 564139fdb3eSNinad Palsule } 565139fdb3eSNinad Palsule 566139fdb3eSNinad Palsule type_init(tpm_tis_i2c_register_types) 567