26
26
*/
27
27
28
28
#include "qemu/osdep.h"
29
+ #include "qemu/fifo8.h"
29
30
#include "qemu/typedefs.h"
30
31
#include "qom/object.h"
31
32
#include "chardev/char-fe.h"
32
33
#include "hw/i2c/i2c.h"
33
34
#include "hw/opentitan/ot_i2c_transport.h"
34
35
#include "hw/qdev-properties-system.h"
35
36
#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 ;
36
50
37
51
struct OtI2CTransportState {
38
52
I2CSlave parent_obj ;
39
53
I2CBus * bus ;
40
54
55
+ Fifo8 cmd_bytes_fifo ;
56
+ CmdParserState parser_state ;
57
+ bool is_read_command ;
58
+ uint8_t byte ;
59
+
41
60
CharBackend chr ;
42
61
};
43
62
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
+
44
189
static int ot_i2c_transport_can_receive (void * opaque )
45
190
{
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 ;
48
195
}
49
196
50
197
static void ot_i2c_transport_receive (void * opaque , const uint8_t * buf , int size )
51
198
{
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
+ }
55
208
}
56
209
57
210
static void ot_i2c_transport_realize (DeviceState * dev , Error * * errp )
@@ -68,7 +221,10 @@ static void ot_i2c_transport_realize(DeviceState *dev, Error **errp)
68
221
static void ot_i2c_transport_init (Object * obj )
69
222
{
70
223
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 ;
72
228
}
73
229
74
230
static Property ot_i2c_transport_properties [] = {
0 commit comments