xref: /openbmc/qemu/hw/tpm/tpm_tis_i2c.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
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     return;
216139fdb3eSNinad Palsule }
217139fdb3eSNinad Palsule 
218139fdb3eSNinad Palsule /* Send data to TPM */
tpm_tis_i2c_tpm_send(TPMStateI2C * i2cst)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 */
tpm_tis_i2c_request_completed(TPMIf * ti,int ret)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 
tpm_tis_i2c_get_tpm_version(TPMIf * ti)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 
tpm_tis_i2c_event(I2CSlave * i2c,enum i2c_event event)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  */
tpm_tis_i2c_recv(I2CSlave * i2c)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  */
tpm_tis_i2c_send(I2CSlave * i2c,uint8_t data)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 
tpm_tis_i2c_realizefn(DeviceState * dev,Error ** errp)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     /*
5106eedbb5bSMichael 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 
tpm_tis_i2c_reset(DeviceState * dev)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 
tpm_tis_i2c_class_init(ObjectClass * klass,void * data)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;
541*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, 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 
tpm_tis_i2c_register_types(void)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