xref: /qemu/hw/tpm/tpm_tis_i2c.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
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 
tpm_tis_i2c_pre_save(void * opaque)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 
tpm_tis_i2c_post_load(void * opaque,int version_id)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  */
tpm_tis_i2c_set_data(TPMStateI2C * i2cst,uint32_t data)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  */
tpm_tis_i2c_interface_capability(TPMStateI2C * i2cst,uint32_t tis_cap)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 */
tpm_tis_i2c_to_tis_reg(TPMStateI2C * i2cst,uint8_t i2c_reg)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. */
tpm_tis_i2c_clear_data(TPMStateI2C * i2cst)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 */
tpm_tis_i2c_tpm_send(TPMStateI2C * i2cst)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 */
tpm_tis_i2c_request_completed(TPMIf * ti,int ret)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 
tpm_tis_i2c_get_tpm_version(TPMIf * ti)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 
tpm_tis_i2c_event(I2CSlave * i2c,enum i2c_event event)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  */
tpm_tis_i2c_recv(I2CSlave * i2c)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  */
tpm_tis_i2c_send(I2CSlave * i2c,uint8_t data)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 
tpm_tis_i2c_realizefn(DeviceState * dev,Error ** errp)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 
tpm_tis_i2c_reset(DeviceState * dev)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 
tpm_tis_i2c_class_init(ObjectClass * klass,const void * data)52912d1a768SPhilippe 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,
555*2cd09e47SPhilippe Mathieu-Daudé         .interfaces = (const InterfaceInfo[]) {
556139fdb3eSNinad Palsule         { TYPE_TPM_IF },
557139fdb3eSNinad Palsule         { }
558139fdb3eSNinad Palsule     }
559139fdb3eSNinad Palsule };
560139fdb3eSNinad Palsule 
tpm_tis_i2c_register_types(void)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