Skip to content

Commit adb240e

Browse files
committed
[ot] hw/opentitan: ot_i2c_transport: initial implementation
Initial implementation. See top comment on description of the wire protocol. Signed-off-by: Alice Ziuziakowska <[email protected]>
1 parent 97d575f commit adb240e

File tree

1 file changed

+162
-6
lines changed

1 file changed

+162
-6
lines changed

hw/opentitan/ot_i2c_transport.c

Lines changed: 162 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,32 +26,185 @@
2626
*/
2727

2828
#include "qemu/osdep.h"
29+
#include "qemu/fifo8.h"
2930
#include "qemu/typedefs.h"
3031
#include "qom/object.h"
3132
#include "chardev/char-fe.h"
3233
#include "hw/i2c/i2c.h"
3334
#include "hw/opentitan/ot_i2c_transport.h"
3435
#include "hw/qdev-properties-system.h"
3536
#include "hw/qdev-properties.h"
37+
#include "hw/sysbus.h"
38+
#include "trace.h"
39+
40+
#define CMD_FIFO_SIZE 256u
41+
42+
typedef enum {
43+
OT_I2C_CMD_INIT,
44+
OT_I2C_CMD_ADDR_1,
45+
OT_I2C_CMD_ADDR_2,
46+
OT_I2C_CMD_PAYLOAD_1,
47+
OT_I2C_CMD_PAYLOAD_2,
48+
OT_I2C_CMD_BYTE,
49+
} CmdParserState;
3650

3751
struct OtI2CTransportState {
3852
I2CSlave parent_obj;
3953
I2CBus *bus;
4054

55+
Fifo8 cmd_bytes_fifo;
56+
CmdParserState parser_state;
57+
bool is_read_command;
58+
uint8_t byte;
59+
4160
CharBackend chr;
4261
};
4362

63+
static void ot_i2c_transport_put_send_failure(OtI2CTransportState *s)
64+
{
65+
uint8_t fmt_byte[2] = { '!', '!' };
66+
qemu_chr_fe_write(&s->chr, fmt_byte, ARRAY_SIZE(fmt_byte));
67+
}
68+
69+
static void
70+
ot_i2c_transport_put_formatted_byte(OtI2CTransportState *s, uint8_t data)
71+
{
72+
char hex[16] = "0123456789ABCDEF";
73+
uint8_t fmt_byte[2] = { hex[data >> 4u], hex[data & 0xfu] };
74+
qemu_chr_fe_write(&s->chr, fmt_byte, ARRAY_SIZE(fmt_byte));
75+
}
76+
77+
static void ot_i2c_transport_start_transfer(OtI2CTransportState *s)
78+
{
79+
if (i2c_start_transfer(s->bus, s->byte, s->is_read_command) != 0) {
80+
ot_i2c_transport_put_send_failure(s);
81+
} else {
82+
ot_i2c_transport_put_formatted_byte(s, s->byte);
83+
}
84+
}
85+
86+
static void ot_i2c_transport_do_read(OtI2CTransportState *s)
87+
{
88+
ot_i2c_transport_put_formatted_byte(s, i2c_recv(s->bus));
89+
}
90+
91+
static void ot_i2c_transport_do_write(OtI2CTransportState *s)
92+
{
93+
if (i2c_send(s->bus, s->byte) != 0) {
94+
ot_i2c_transport_put_send_failure(s);
95+
} else {
96+
ot_i2c_transport_put_formatted_byte(s, s->byte);
97+
}
98+
}
99+
100+
static void ot_i2c_transport_command_byte(OtI2CTransportState *s, uint8_t byte)
101+
{
102+
gint nibble;
103+
gchar ch = (gchar)byte;
104+
switch (s->parser_state) {
105+
case OT_I2C_CMD_INIT:
106+
/* parse either a R or W for a read or write command */
107+
if (byte != 'R' && byte != 'W') {
108+
break;
109+
}
110+
s->is_read_command = byte == 'R';
111+
s->byte = 0u;
112+
s->parser_state = OT_I2C_CMD_ADDR_1;
113+
break;
114+
case OT_I2C_CMD_ADDR_1:
115+
/* parse first nibble of address byte */
116+
if (byte == '\n' || byte == ' ') {
117+
break;
118+
}
119+
nibble = g_ascii_xdigit_value(ch);
120+
if (nibble < 0) {
121+
s->parser_state = OT_I2C_CMD_INIT;
122+
break;
123+
}
124+
s->byte = (uint8_t)nibble;
125+
s->parser_state = OT_I2C_CMD_ADDR_2;
126+
break;
127+
case OT_I2C_CMD_ADDR_2:
128+
/* parse second nibble of address byte */
129+
nibble = g_ascii_xdigit_value(ch);
130+
if (nibble < 0) {
131+
s->parser_state = OT_I2C_CMD_INIT;
132+
break;
133+
}
134+
s->byte = (s->byte << 4u) | (uint8_t)nibble;
135+
ot_i2c_transport_start_transfer(s);
136+
s->parser_state =
137+
s->is_read_command ? OT_I2C_CMD_BYTE : OT_I2C_CMD_PAYLOAD_1;
138+
break;
139+
case OT_I2C_CMD_PAYLOAD_1:
140+
/* parse first nibble of write payload byte */
141+
if (byte == '\n' || byte == ' ') {
142+
break;
143+
}
144+
/* signal no more bytes to write with an S */
145+
if (byte == 'S') {
146+
s->parser_state = OT_I2C_CMD_INIT;
147+
i2c_end_transfer(s->bus);
148+
break;
149+
}
150+
nibble = g_ascii_xdigit_value(ch);
151+
if (nibble < 0) {
152+
s->parser_state = OT_I2C_CMD_INIT;
153+
i2c_end_transfer(s->bus);
154+
break;
155+
}
156+
s->byte = (uint8_t)nibble;
157+
s->parser_state = OT_I2C_CMD_PAYLOAD_2;
158+
break;
159+
case OT_I2C_CMD_PAYLOAD_2:
160+
/* parse second nibble of write payload byte */
161+
nibble = g_ascii_xdigit_value(ch);
162+
if (nibble < 0) {
163+
s->parser_state = OT_I2C_CMD_INIT;
164+
i2c_end_transfer(s->bus);
165+
break;
166+
}
167+
s->byte = (s->byte << 4u) | (uint8_t)nibble;
168+
ot_i2c_transport_do_write(s);
169+
s->parser_state = OT_I2C_CMD_PAYLOAD_1;
170+
break;
171+
case OT_I2C_CMD_BYTE:
172+
/* parse a B to read a byte from the I2C bus */
173+
if (byte == '\n' || byte == ' ') {
174+
break;
175+
}
176+
if (byte == 'B') {
177+
ot_i2c_transport_do_read(s);
178+
s->parser_state = OT_I2C_CMD_BYTE;
179+
} else {
180+
i2c_end_transfer(s->bus);
181+
s->parser_state = OT_I2C_CMD_INIT;
182+
}
183+
break;
184+
default:
185+
g_assert_not_reached();
186+
}
187+
}
188+
44189
static int ot_i2c_transport_can_receive(void *opaque)
45190
{
46-
(void)opaque;
47-
return 1;
191+
OtI2CTransportState *s = OT_I2C_TRANSPORT(opaque);
192+
int num_free = (int)fifo8_num_free(&s->cmd_bytes_fifo);
193+
g_assert(num_free >= 0);
194+
return num_free;
48195
}
49196

50197
static void ot_i2c_transport_receive(void *opaque, const uint8_t *buf, int size)
51198
{
52-
(void)opaque;
53-
(void)buf;
54-
(void)size;
199+
OtI2CTransportState *s = OT_I2C_TRANSPORT(opaque);
200+
g_assert(fifo8_num_free(&s->cmd_bytes_fifo) >= size);
201+
fifo8_push_all(&s->cmd_bytes_fifo, buf, size);
202+
203+
/* Drive the command state machine with each byte */
204+
while (!fifo8_is_empty(&s->cmd_bytes_fifo)) {
205+
uint8_t byte = fifo8_pop(&s->cmd_bytes_fifo);
206+
ot_i2c_transport_command_byte(s, byte);
207+
}
55208
}
56209

57210
static void ot_i2c_transport_realize(DeviceState *dev, Error **errp)
@@ -68,7 +221,10 @@ static void ot_i2c_transport_realize(DeviceState *dev, Error **errp)
68221
static void ot_i2c_transport_init(Object *obj)
69222
{
70223
OtI2CTransportState *s = OT_I2C_TRANSPORT(obj);
71-
(void)s;
224+
fifo8_create(&s->cmd_bytes_fifo, CMD_FIFO_SIZE);
225+
s->parser_state = OT_I2C_CMD_INIT;
226+
s->is_read_command = false;
227+
s->byte = 0u;
72228
}
73229

74230
static Property ot_i2c_transport_properties[] = {

0 commit comments

Comments
 (0)