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