xref: /openbmc/qemu/include/hw/i3c/dw-i3c.h (revision 5a2a5453bac7daafcdf0601a91009e01345b1dd2)
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/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 typedef struct DWI3C {
167     /* <private> */
168     SysBusDevice parent;
169 
170     /* <public> */
171     MemoryRegion mr;
172     qemu_irq irq;
173     I3CBus *bus;
174 
175     Fifo32 cmd_queue;
176     Fifo32 resp_queue;
177     Fifo32 tx_queue;
178     Fifo32 rx_queue;
179     Fifo32 ibi_queue;
180 
181     /* Temporary storage for IBI data. */
182     DWI3CIBIData ibi_data;
183 
184     struct {
185         uint8_t id;
186         uint8_t cmd_resp_queue_capacity_bytes;
187         uint16_t tx_rx_queue_capacity_bytes;
188         uint8_t ibi_queue_capacity_bytes;
189         uint8_t num_addressable_devices;
190         uint16_t dev_addr_table_pointer;
191         uint16_t dev_addr_table_depth;
192         uint16_t dev_char_table_pointer;
193         uint16_t dev_char_table_depth;
194     } cfg;
195     uint32_t regs[DW_I3C_NR_REGS];
196 } DWI3C;
197 
198 /* Extern for other controllers that use DesignWare I3C. */
199 extern const VMStateDescription vmstate_dw_i3c;
200 
201 #endif /* DW_I3C_H */
202