master
h 199 lines 5.84 KB
Raw
1 /*
2 * DesignWare I3C Controller
3 *
4 * Copyright (C) 2021 ASPEED Technology Inc.
5 * Copyright (C) 2025 Google, LLC.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #ifndef DW_I3C_H
11 #define DW_I3C_H
12
13 #include "qemu/fifo32.h"
14 #include "hw/i3c/i3c.h"
15 #include "hw/core/sysbus.h"
16
17 #define TYPE_DW_I3C "dw.i3c"
18 OBJECT_DECLARE_SIMPLE_TYPE(DWI3C, DW_I3C)
19
20 /*
21 * Sufficiently large enough to handle configurations with large device address
22 * tables.
23 */
24 #define DW_I3C_NR_REGS (0x1000 >> 2)
25
26 /* From datasheet. */
27 #define DW_I3C_CMD_ATTR_TRANSFER_CMD 0
28 #define DW_I3C_CMD_ATTR_TRANSFER_ARG 1
29 #define DW_I3C_CMD_ATTR_SHORT_DATA_ARG 2
30 #define DW_I3C_CMD_ATTR_ADDR_ASSIGN_CMD 3
31
32 /* Enum values from datasheet. */
33 typedef enum DWI3CRespQueueErr {
34 DW_I3C_RESP_QUEUE_ERR_NONE = 0,
35 DW_I3C_RESP_QUEUE_ERR_CRC = 1,
36 DW_I3C_RESP_QUEUE_ERR_PARITY = 2,
37 DW_I3C_RESP_QUEUE_ERR_FRAME = 3,
38 DW_I3C_RESP_QUEUE_ERR_BROADCAST_NACK = 4,
39 DW_I3C_RESP_QUEUE_ERR_DAA_NACK = 5,
40 DW_I3C_RESP_QUEUE_ERR_OVERFLOW = 6,
41 DW_I3C_RESP_QUEUE_ERR_ABORTED = 8,
42 DW_I3C_RESP_QUEUE_ERR_I2C_NACK = 9,
43 } DWI3CRespQueueErr;
44
45 typedef enum DWI3CTransferState {
46 DW_I3C_TRANSFER_STATE_IDLE = 0x00,
47 DW_I3C_TRANSFER_STATE_START = 0x01,
48 DW_I3C_TRANSFER_STATE_RESTART = 0x02,
49 DW_I3C_TRANSFER_STATE_STOP = 0x03,
50 DW_I3C_TRANSFER_STATE_START_HOLD = 0x04,
51 DW_I3C_TRANSFER_STATE_BROADCAST_W = 0x05,
52 DW_I3C_TRANSFER_STATE_BROADCAST_R = 0x06,
53 DW_I3C_TRANSFER_STATE_DAA = 0x07,
54 DW_I3C_TRANSFER_STATE_DAA_GEN = 0x08,
55 DW_I3C_TRANSFER_STATE_CCC_BYTE = 0x0b,
56 DW_I3C_TRANSFER_STATE_HDR_CMD = 0x0c,
57 DW_I3C_TRANSFER_STATE_WRITE = 0x0d,
58 DW_I3C_TRANSFER_STATE_READ = 0x0e,
59 DW_I3C_TRANSFER_STATE_IBI_READ = 0x0f,
60 DW_I3C_TRANSFER_STATE_IBI_DIS = 0x10,
61 DW_I3C_TRANSFER_STATE_HDR_DDR_CRC = 0x11,
62 DW_I3C_TRANSFER_STATE_CLK_STRETCH = 0x12,
63 DW_I3C_TRANSFER_STATE_HALT = 0x13,
64 } DWI3CTransferState;
65
66 typedef enum DWI3CTransferStatus {
67 DW_I3C_TRANSFER_STATUS_IDLE = 0x00,
68 DW_I3C_TRANSFER_STATUS_BROACAST_CCC = 0x01,
69 DW_I3C_TRANSFER_STATUS_DIRECT_CCC_W = 0x02,
70 DW_I3C_TRANSFER_STATUS_DIRECT_CCC_R = 0x03,
71 DW_I3C_TRANSFER_STATUS_ENTDAA = 0x04,
72 DW_I3C_TRANSFER_STATUS_SETDASA = 0x05,
73 DW_I3C_TRANSFER_STATUS_I3C_SDR_W = 0x06,
74 DW_I3C_TRANSFER_STATUS_I3C_SDR_R = 0x07,
75 DW_I3C_TRANSFER_STATUS_I2C_SDR_W = 0x08,
76 DW_I3C_TRANSFER_STATUS_I2C_SDR_R = 0x09,
77 DW_I3C_TRANSFER_STATUS_HDR_TS_W = 0x0a,
78 DW_I3C_TRANSFER_STATUS_HDR_TS_R = 0x0b,
79 DW_I3C_TRANSFER_STATUS_HDR_DDR_W = 0x0c,
80 DW_I3C_TRANSFER_STATUS_HDR_DDR_R = 0x0d,
81 DW_I3C_TRANSFER_STATUS_IBI = 0x0e,
82 DW_I3C_TRANSFER_STATUS_HALT = 0x0f,
83 } DWI3CTransferStatus;
84
85 /*
86 * Transfer commands and arguments are 32-bit wide values that the user passes
87 * into the command queue. We interpret each 32-bit word based on the cmd_attr
88 * field.
89 */
90 typedef struct DWI3CTransferCmd {
91 uint8_t cmd_attr:3;
92 uint8_t tid:4; /* Transaction ID */
93 uint16_t cmd:8;
94 uint8_t cp:1; /* Command present */
95 uint8_t dev_index:5;
96 uint8_t speed:3;
97 uint8_t resv0:1;
98 uint8_t dbp:1; /* Defining byte present */
99 uint8_t roc:1; /* Response on completion */
100 uint8_t sdap:1; /* Short data argument present */
101 uint8_t rnw:1; /* Read not write */
102 uint8_t resv1:1;
103 uint8_t toc:1; /* Termination (I3C STOP) on completion */
104 uint8_t pec:1; /* Parity error check enabled */
105 } DWI3CTransferCmd;
106
107 typedef struct DWI3CTransferArg {
108 uint8_t cmd_attr:3;
109 uint8_t resv:5;
110 uint8_t db; /* Defining byte */
111 uint16_t data_len;
112 } DWI3CTransferArg;
113
114 typedef struct DWI3CShortArg {
115 uint8_t cmd_attr:3;
116 uint8_t byte_strb:3;
117 uint8_t resv:2;
118 uint8_t byte0;
119 uint8_t byte1;
120 uint8_t byte2;
121 } DWI3CShortArg;
122
123 typedef struct DWI3CAddrAssignCmd {
124 uint8_t cmd_attr:3;
125 uint8_t tid:4; /* Transaction ID */
126 uint16_t cmd:8;
127 uint8_t resv0:1;
128 uint8_t dev_index:5;
129 uint16_t dev_count:5;
130 uint8_t roc:1; /* Response on completion */
131 uint8_t resv1:3;
132 uint8_t toc:1; /* Termination (I3C STOP) on completion */
133 uint8_t resv2:1;
134 } DWI3CAddrAssignCmd;
135
136 typedef union DWI3CCmdQueueData {
137 uint32_t word;
138 DWI3CTransferCmd transfer_cmd;
139 DWI3CTransferArg transfer_arg;
140 DWI3CShortArg short_arg;
141 DWI3CAddrAssignCmd addr_assign_cmd;
142 } DWI3CCmdQueueData;
143
144 /*
145 * When we receive an IBI with data, we need to store it temporarily until
146 * the target is finished sending data. Then we can set the IBI queue status
147 * appropriately.
148 */
149 typedef struct DWI3CIBIData {
150 /* Do we notify the user that an IBI was NACKed? */
151 bool notify_ibi_nack;
152 /* Intermediate storage of IBI_QUEUE_STATUS. */
153 uint32_t ibi_queue_status;
154 /* Temporary buffer to store IBI data from the target. */
155 Fifo8 ibi_intermediate_queue;
156 /* The address we should send a CCC_DISEC to. */
157 uint8_t disec_addr;
158 /* The byte we should send along with the CCC_DISEC. */
159 uint8_t disec_byte;
160 /* Should we send a direct DISEC CCC? (As opposed to global). */
161 bool send_direct_disec;
162 /* Was this IBI NACKed? */
163 bool ibi_nacked;
164 } DWI3CIBIData;
165
166 struct DWI3C {
167 SysBusDevice parent_obj;
168
169 MemoryRegion mr;
170 qemu_irq irq;
171 I3CBus *bus;
172
173 Fifo32 cmd_queue;
174 Fifo32 resp_queue;
175 Fifo32 tx_queue;
176 Fifo32 rx_queue;
177 Fifo32 ibi_queue;
178
179 /* Temporary storage for IBI data. */
180 DWI3CIBIData ibi_data;
181
182 struct {
183 uint8_t id;
184 uint8_t cmd_resp_queue_capacity_words;
185 uint16_t tx_rx_queue_capacity_words;
186 uint8_t ibi_queue_capacity_words;
187 uint8_t num_addressable_devices;
188 uint16_t dev_addr_table_pointer;
189 uint16_t dev_addr_table_depth;
190 uint16_t dev_char_table_pointer;
191 uint16_t dev_char_table_depth;
192 } cfg;
193 uint32_t regs[DW_I3C_NR_REGS];
194 };
195
196 /* Extern for other controllers that use DesignWare I3C. */
197 extern const VMStateDescription vmstate_dw_i3c;
198
199 #endif /* DW_I3C_H */