@samitouri / QOSamiQemu / commits / 8dd2e138be

hw/i2c: Add DesignWare I2C Controller

Add a model for the Synopsys DesignWare Advanced I2C/SMBus Controller with sufficient functionality to be used by the Linux Designware I2C platform driver. This IP is used in the Tenstorrent Atlantis RISC-V SoC and will be added to the QEMU tt-atlantis machine. [npiggin: changelog, code cleanups and fixes as-per below link] Reviewed-by: Hao Wu <wuhaotsh@google.com> Signed-off-by: Chris Rauer <crauer@google.com> Link: https://lore.kernel.org/qemu-devel/20220110214755.810343-2-venture@google.com [jms: rebase and minor build fixes for class_init and reset callback] Link: https://lore.kernel.org/qemu-devel/20260507120524.111056-1-npiggin@gmail.com Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Acked-by: Corey Minyard <cminyard@mvista.com> Tested-by: Alano Song <AlanoSong@163.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Message-ID: <20260630024952.1520546-11-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

Chris Rauer committed Jun 30, 2026 at 12:19 UTC 8dd2e138bec76126867bb21891a745c6ad1e8b42
5 files changed +815
MAINTAINERS
+8
@@ -2766,6 +2766,14 @@ S: Orphan
2766 F: hw/gpio/pcf8574.c
2767 F: include/hw/gpio/pcf8574.h
2768
2769 +DesignWare I2C
2770 +M: Chris Rauer <crauer@google.com>
2771 +R: Alano Song <alanosong@163.com>
2772 +R: Joel Stanley <joel@jms.id.au>
2773 +S: Maintained
2774 +F: hw/i2c/designware_i2c.c
2775 +F: include/hw/i2c/designware_i2c.h
2776 +
2777 Generic Loader
2778 M: Alistair Francis <alistair@alistair23.me>
2779 S: Maintained
hw/i2c/Kconfig
+5
@@ -18,6 +18,11 @@ config ARM_SBCON_I2C
18 bool
19 select BITBANG_I2C
20
21 +config DESIGNWARE_I2C
22 + bool
23 + select REGISTER
24 + select I2C
25 +
26 config ACPI_SMBUS
27 bool
28 select SMBUS
hw/i2c/designware_i2c.c new
+745
@@ -0,0 +1,745 @@
1 +/*
2 + * DesignWare I2C Module.
3 + *
4 + * Copyright 2021 Google LLC
5 + *
6 + * SPDX-License-Identifier: GPL-2.0-or-later
7 + */
8 +
9 +#include "qemu/osdep.h"
10 +
11 +#include "hw/i2c/designware_i2c.h"
12 +#include "migration/vmstate.h"
13 +#include "qemu/log.h"
14 +#include "qemu/module.h"
15 +#include "qemu/units.h"
16 +
17 +#ifndef DESIGNWARE_I2C_ERR_DEBUG
18 +#define DESIGNWARE_I2C_ERR_DEBUG 0
19 +#endif
20 +
21 +REG32(DW_IC_CON, 0x00) /* I2C control */
22 + FIELD(DW_IC_CON, STOP_DET_IF_MASTER_ACTIV, 10, 1)
23 + FIELD(DW_IC_CON, RX_FIFO_FULL_HLD_CTRL, 9, 1)
24 + FIELD(DW_IC_CON, TX_EMPTY_CTRL, 8, 1)
25 + FIELD(DW_IC_CON, STOP_IF_ADDRESSED, 7, 1)
26 + FIELD(DW_IC_CON, SLAVE_DISABLE, 6, 1)
27 + FIELD(DW_IC_CON, IC_RESTART_EN, 5, 1)
28 + FIELD(DW_IC_CON, 10BITADDR_MASTER, 4, 1)
29 + FIELD(DW_IC_CON, 10BITADDR_SLAVE, 3, 1)
30 + FIELD(DW_IC_CON, SPEED, 1, 2)
31 + FIELD(DW_IC_CON, MASTER_MODE, 0, 1)
32 +REG32(DW_IC_TAR, 0x04) /* I2C target address */
33 + FIELD(DW_IC_TAR, IC_10BITADDR_MASTER, 12, 1)
34 + FIELD(DW_IC_TAR, SPECIAL, 11, 1)
35 + FIELD(DW_IC_TAR, GC_OR_START, 10, 1)
36 + FIELD(DW_IC_TAR, ADDRESS, 0, 10)
37 +REG32(DW_IC_SAR, 0x08) /* I2C slave address */
38 +REG32(DW_IC_DATA_CMD, 0x10)
39 + FIELD(DW_IC_DATA_CMD, RESTART, 10, 1)
40 + FIELD(DW_IC_DATA_CMD, STOP, 9, 1)
41 + FIELD(DW_IC_DATA_CMD, CMD, 8, 1)
42 + FIELD(DW_IC_DATA_CMD, DAT, 0, 8)
43 +REG32(DW_IC_SS_SCL_HCNT, 0x14) /* Standard speed i2c clock scl high count */
44 +REG32(DW_IC_SS_SCL_LCNT, 0x18) /* Standard speed i2c clock scl low count */
45 +REG32(DW_IC_FS_SCL_HCNT, 0x1c) /* Fast or fast plus i2c clock scl high count */
46 +REG32(DW_IC_FS_SCL_LCNT, 0x20) /* Fast or fast plus i2c clock scl low count */
47 +REG32(DW_IC_INTR_STAT, 0x2c)
48 +REG32(DW_IC_INTR_MASK, 0x30) /* I2C Interrupt Mask */
49 +REG32(DW_IC_RAW_INTR_STAT, 0x34) /* I2C raw interrupt status */
50 + /* DW_IC_INTR_STAT/INTR_MASK/RAW_INTR_STAT fields */
51 + SHARED_FIELD(DW_IC_INTR_RESTART_DET, 12, 1)
52 + SHARED_FIELD(DW_IC_INTR_GEN_CALL, 11, 1)
53 + SHARED_FIELD(DW_IC_INTR_START_DET, 10, 1)
54 + SHARED_FIELD(DW_IC_INTR_STOP_DET, 9, 1)
55 + SHARED_FIELD(DW_IC_INTR_ACTIVITY, 8, 1)
56 + SHARED_FIELD(DW_IC_INTR_RX_DONE, 7, 1)
57 + SHARED_FIELD(DW_IC_INTR_TX_ABRT, 6, 1)
58 + SHARED_FIELD(DW_IC_INTR_RD_REQ, 5, 1)
59 + SHARED_FIELD(DW_IC_INTR_TX_EMPTY, 4, 1) /* Hardware clear only. */
60 + SHARED_FIELD(DW_IC_INTR_TX_OVER, 3, 1)
61 + SHARED_FIELD(DW_IC_INTR_RX_FULL, 2, 1) /* Hardware clear only. */
62 + SHARED_FIELD(DW_IC_INTR_RX_OVER, 1, 1)
63 + SHARED_FIELD(DW_IC_INTR_RX_UNDER, 0, 1)
64 +
65 +#define DW_IC_INTR_ANY_MASK \
66 + (DW_IC_INTR_RESTART_DET_MASK | \
67 + DW_IC_INTR_GEN_CALL_MASK | \
68 + DW_IC_INTR_START_DET_MASK | \
69 + DW_IC_INTR_STOP_DET_MASK | \
70 + DW_IC_INTR_ACTIVITY_MASK | \
71 + DW_IC_INTR_RX_DONE_MASK | \
72 + DW_IC_INTR_TX_ABRT_MASK | \
73 + DW_IC_INTR_RD_REQ_MASK | \
74 + DW_IC_INTR_TX_EMPTY_MASK | \
75 + DW_IC_INTR_TX_OVER_MASK | \
76 + DW_IC_INTR_RX_FULL_MASK | \
77 + DW_IC_INTR_RX_OVER_MASK | \
78 + DW_IC_INTR_RX_UNDER_MASK)
79 +
80 +#define DW_IC_INTR_ANY_SW_CLEAR_MASK \
81 + (DW_IC_INTR_ANY_MASK & \
82 + ~(DW_IC_INTR_TX_EMPTY_MASK | \
83 + DW_IC_INTR_RX_FULL_MASK))
84 +
85 +REG32(DW_IC_RX_TL, 0x38) /* I2C receive FIFO threshold */
86 +REG32(DW_IC_TX_TL, 0x3c) /* I2C transmit FIFO threshold */
87 +REG32(DW_IC_CLR_INTR, 0x40)
88 +REG32(DW_IC_CLR_RX_UNDER, 0x44)
89 +REG32(DW_IC_CLR_RX_OVER, 0x48)
90 +REG32(DW_IC_CLR_TX_OVER, 0x4c)
91 +REG32(DW_IC_CLR_RD_REQ, 0x50)
92 +REG32(DW_IC_CLR_TX_ABRT, 0x54)
93 +REG32(DW_IC_CLR_RX_DONE, 0x58)
94 +REG32(DW_IC_CLR_ACTIVITY, 0x5c)
95 +REG32(DW_IC_CLR_STOP_DET, 0x60)
96 +REG32(DW_IC_CLR_START_DET, 0x64)
97 +REG32(DW_IC_CLR_GEN_CALL, 0x68)
98 +REG32(DW_IC_ENABLE, 0x6c) /* I2C enable */
99 + FIELD(DW_IC_ENABLE, TX_CMD_BLOCK, 2, 1)
100 + FIELD(DW_IC_ENABLE, ABORT, 1, 1)
101 + FIELD(DW_IC_ENABLE, ENABLE, 0, 1)
102 +REG32(DW_IC_STATUS, 0x70) /* I2C status */
103 + FIELD(DW_IC_STATUS, SLV_ACTIVITY, 6, 1)
104 + FIELD(DW_IC_STATUS, MST_ACTIVITY, 5, 1)
105 + FIELD(DW_IC_STATUS, RFF, 4, 1)
106 + FIELD(DW_IC_STATUS, RFNE, 3, 1)
107 + FIELD(DW_IC_STATUS, TFE, 2, 1)
108 + FIELD(DW_IC_STATUS, TFNF, 1, 1)
109 + FIELD(DW_IC_STATUS, ACTIVITY, 0, 1)
110 +REG32(DW_IC_TXFLR, 0x74) /* I2C transmit fifo level */
111 +REG32(DW_IC_RXFLR, 0x78) /* I2C receive fifo level */
112 +REG32(DW_IC_SDA_HOLD, 0x7c) /* I2C SDA hold time length */
113 +REG32(DW_IC_TX_ABRT_SOURCE, 0x80) /* The I2C transmit abort source */
114 + FIELD(DW_IC_TX_ABRT_SOURCE, USER_ABRT, 16, 1)
115 + FIELD(DW_IC_TX_ABRT_SOURCE, SLVRD_INTX, 15, 1)
116 + FIELD(DW_IC_TX_ABRT_SOURCE, SLV_ARBLOST, 14, 1)
117 + FIELD(DW_IC_TX_ABRT_SOURCE, SLVFLUSH_TXFIFO, 13, 1)
118 + FIELD(DW_IC_TX_ABRT_SOURCE, ARB_LOST, 12, 1)
119 + FIELD(DW_IC_TX_ABRT_SOURCE, MASTER_DIS, 11, 1)
120 + FIELD(DW_IC_TX_ABRT_SOURCE, 10B_RD_NORSTRT, 10, 1)
121 + FIELD(DW_IC_TX_ABRT_SOURCE, SBYTE_NORSTRT, 9, 1)
122 + FIELD(DW_IC_TX_ABRT_SOURCE, HS_NORSTRT, 8, 1)
123 + FIELD(DW_IC_TX_ABRT_SOURCE, SBYTE_ACKDET, 7, 1)
124 + FIELD(DW_IC_TX_ABRT_SOURCE, HS_ACKDET, 6, 1)
125 + FIELD(DW_IC_TX_ABRT_SOURCE, GCALL_READ, 5, 1)
126 + FIELD(DW_IC_TX_ABRT_SOURCE, GCALL_NOACK, 4, 1)
127 + FIELD(DW_IC_TX_ABRT_SOURCE, TXDATA_NOACK, 3, 1)
128 + FIELD(DW_IC_TX_ABRT_SOURCE, 10ADDR2_NOACK, 2, 1)
129 + FIELD(DW_IC_TX_ABRT_SOURCE, 10ADDR1_NOACK, 1, 1)
130 + FIELD(DW_IC_TX_ABRT_SOURCE, 7B_ADDR_NOACK, 0, 1)
131 +REG32(DW_IC_SLV_DATA_NACK_ONLY, 0x84)
132 +REG32(DW_IC_DMA_CR, 0x88)
133 +REG32(DW_IC_DMA_TDLR, 0x8c)
134 +REG32(DW_IC_DMA_RDLR, 0x90)
135 +REG32(DW_IC_SDA_SETUP, 0x94) /* I2C SDA setup */
136 +REG32(DW_IC_ACK_GENERAL_CALL, 0x98)
137 +REG32(DW_IC_ENABLE_STATUS, 0x9c) /* I2C enable status */
138 + FIELD(DW_IC_ENABLE_STATUS, SLV_RX_DATA_LOST, 2, 1)
139 + FIELD(DW_IC_ENABLE_STATUS, SLV_DISABLED_WHILE_BUSY, 1, 1)
140 + FIELD(DW_IC_ENABLE_STATUS, IC_EN, 0, 1)
141 +REG32(DW_IC_FS_SPKLEN, 0xa0) /* I2C SS, FS or FM+ spike suppression limit */
142 +REG32(DW_IC_CLR_RESTART_DET, 0xa8)
143 +REG32(DW_IC_SMBUS_INTR_MASK, 0xcc) /* SMBus Interrupt Mask */
144 +REG32(DW_IC_COMP_PARAM_1, 0xf4) /* Component parameter */
145 + FIELD(DW_IC_COMP_PARAM_1, TX_FIFO_SIZE, 16, 8)
146 + FIELD(DW_IC_COMP_PARAM_1, RX_FIFO_SIZE, 8, 8)
147 + FIELD(DW_IC_COMP_PARAM_1, HAS_ENCODED_PARAMS, 7, 1)
148 + FIELD(DW_IC_COMP_PARAM_1, HAS_DMA, 6, 1)
149 + FIELD(DW_IC_COMP_PARAM_1, INTR_IO, 5, 1)
150 + FIELD(DW_IC_COMP_PARAM_1, HC_COUNT_VAL, 4, 1)
151 + FIELD(DW_IC_COMP_PARAM_1, HIGH_SPEED_MODE, 2, 2)
152 + FIELD(DW_IC_COMP_PARAM_1, APB_DATA_WIDTH_32, 0, 2)
153 +REG32(DW_IC_COMP_VERSION, 0xf8) /* I2C component version */
154 +REG32(DW_IC_COMP_TYPE, 0xfc) /* I2C component type */
155 +
156 +static void dw_i2c_update_irq(DesignWareI2CState *s)
157 +{
158 + uint32_t intr = s->regs[R_DW_IC_RAW_INTR_STAT] & s->regs[R_DW_IC_INTR_MASK];
159 +
160 + qemu_set_irq(s->irq, !!(intr & DW_IC_INTR_ANY_MASK));
161 +}
162 +
163 +static uint64_t dw_ic_data_cmd_reg_post_read(RegisterInfo *reg, uint64_t value)
164 +{
165 + DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
166 +
167 + g_assert(value == 0);
168 +
169 + if (s->status != DW_I2C_STATUS_RECEIVING) {
170 + qemu_log_mask(LOG_GUEST_ERROR,
171 + "%s: Attempted to read from RX fifo when not in receive "
172 + "state.\n", DEVICE(s)->canonical_path);
173 + if (s->status != DW_I2C_STATUS_IDLE) {
174 + SHARED_ARRAY_FIELD_DP32(s->regs, R_DW_IC_RAW_INTR_STAT,
175 + DW_IC_INTR_RX_UNDER, 1);
176 + dw_i2c_update_irq(s);
177 + }
178 + return 0;
179 + }
180 +
181 + g_assert(s->regs[R_DW_IC_RXFLR] == fifo8_num_used(&s->rx_fifo));
182 +
183 + if (fifo8_is_empty(&s->rx_fifo)) {
184 + SHARED_ARRAY_FIELD_DP32(s->regs, R_DW_IC_RAW_INTR_STAT, DW_IC_INTR_RX_UNDER, 1);
185 + dw_i2c_update_irq(s);
186 + return 0;
187 + }
188 +
189 + s->regs[R_DW_IC_RXFLR]--;
190 + if (s->regs[R_DW_IC_RXFLR] <= s->regs[R_DW_IC_RX_TL]) {
191 + SHARED_ARRAY_FIELD_DP32(s->regs, R_DW_IC_RAW_INTR_STAT, DW_IC_INTR_RX_FULL, 0);
192 + dw_i2c_update_irq(s);
193 + }
194 +
195 + return fifo8_pop(&s->rx_fifo);
196 +}
197 +
198 +static uint64_t dw_ic_clr_intr_reg_post_read(RegisterInfo *reg, uint64_t value)
199 +{
200 + DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
201 +
202 + g_assert(value == 0);
203 +
204 + switch (reg->access->addr) {
205 + case A_DW_IC_CLR_INTR:
206 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_ANY_SW_CLEAR_MASK;
207 + break;
208 + case A_DW_IC_CLR_RX_UNDER:
209 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RX_UNDER_MASK;
210 + break;
211 + case A_DW_IC_CLR_RX_OVER:
212 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RX_OVER_MASK;
213 + break;
214 + case A_DW_IC_CLR_TX_OVER:
215 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_TX_OVER_MASK;
216 + break;
217 + case A_DW_IC_CLR_RD_REQ:
218 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RD_REQ_MASK;
219 + break;
220 + case A_DW_IC_CLR_TX_ABRT:
221 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_TX_ABRT_MASK;
222 + break;
223 + case A_DW_IC_CLR_RX_DONE:
224 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RX_DONE_MASK;
225 + break;
226 + case A_DW_IC_CLR_ACTIVITY:
227 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_ACTIVITY_MASK;
228 + break;
229 + case A_DW_IC_CLR_STOP_DET:
230 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_STOP_DET_MASK;
231 + break;
232 + case A_DW_IC_CLR_START_DET:
233 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_START_DET_MASK;
234 + break;
235 + case A_DW_IC_CLR_GEN_CALL:
236 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_GEN_CALL_MASK;
237 + break;
238 + case A_DW_IC_CLR_RESTART_DET:
239 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RESTART_DET_MASK;
240 + break;
241 + default:
242 + g_assert_not_reached();
243 + }
244 +
245 + dw_i2c_update_irq(s);
246 +
247 + return 0;
248 +}
249 +
250 +static uint64_t dw_ic_intr_stat_reg_post_read(RegisterInfo *reg, uint64_t value)
251 +{
252 + DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
253 +
254 + g_assert(value == 0);
255 +
256 + return s->regs[R_DW_IC_RAW_INTR_STAT] & s->regs[R_DW_IC_INTR_MASK];
257 +}
258 +
259 +static uint64_t dw_ic_unsupported_reg_post_read(RegisterInfo *reg, uint64_t value)
260 +{
261 + DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
262 +
263 + qemu_log_mask(LOG_UNIMP, "%s: unsupported read - %s\n",
264 + DEVICE(s)->canonical_path, reg->access->name);
265 +
266 + return 0;
267 +}
268 +
269 +static uint64_t dw_ic_unsupported_reg_pre_write(RegisterInfo *reg, uint64_t value)
270 +{
271 + DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
272 +
273 + qemu_log_mask(LOG_UNIMP, "%s: unsupported write - %s\n",
274 + DEVICE(s)->canonical_path, reg->access->name);
275 +
276 + return 0;
277 +}
278 +
279 +static uint64_t dw_ic_con_reg_pre_write(RegisterInfo *reg, uint64_t value)
280 +{
281 + DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
282 +
283 + if (s->regs[R_DW_IC_ENABLE] & R_DW_IC_ENABLE_ENABLE_MASK) {
284 + qemu_log_mask(LOG_GUEST_ERROR,
285 + "%s: invalid setting to ic_con %d when ic_enable[0]==1\n",
286 + DEVICE(s)->canonical_path, (int)value);
287 + return s->regs[R_DW_IC_CON]; /* keep old value */
288 + }
289 +
290 + return value;
291 +}
292 +
293 +static void dw_i2c_reset_to_idle(DesignWareI2CState *s)
294 +{
295 + s->regs[R_DW_IC_ENABLE_STATUS] &= ~R_DW_IC_ENABLE_STATUS_IC_EN_MASK;
296 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_TX_EMPTY_MASK;
297 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RX_FULL_MASK;
298 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RX_UNDER_MASK;
299 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RX_OVER_MASK;
300 + s->regs[R_DW_IC_RXFLR] = 0;
301 + fifo8_reset(&s->rx_fifo);
302 + s->regs[R_DW_IC_STATUS] &= ~R_DW_IC_STATUS_ACTIVITY_MASK;
303 + s->status = DW_I2C_STATUS_IDLE;
304 + dw_i2c_update_irq(s);
305 +}
306 +
307 +static void dw_ic_tx_abort(DesignWareI2CState *s, uint32_t src)
308 +{
309 + s->regs[R_DW_IC_TX_ABRT_SOURCE] |= src;
310 + s->regs[R_DW_IC_RAW_INTR_STAT] |= DW_IC_INTR_TX_ABRT_MASK;
311 + dw_i2c_reset_to_idle(s);
312 + dw_i2c_update_irq(s);
313 +}
314 +
315 +static void dw_ic_data_cmd_reg_post_write(RegisterInfo *reg, uint64_t value)
316 +{
317 + DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
318 + int recv = !!(value & R_DW_IC_DATA_CMD_CMD_MASK);
319 +
320 + s->regs[R_DW_IC_DATA_CMD] = 0; /* Register has no storage */
321 +
322 + if (!(s->regs[R_DW_IC_ENABLE] & R_DW_IC_ENABLE_ENABLE_MASK)) {
323 + /*
324 + * Controller is not enabled. The register_reset() path also lands
325 + * here with value == 0, so silently ignore rather than reporting
326 + * a spurious guest error.
327 + */
328 + return;
329 + }
330 +
331 + if (s->status == DW_I2C_STATUS_IDLE ||
332 + s->regs[R_DW_IC_RAW_INTR_STAT] & DW_IC_INTR_TX_ABRT_MASK) {
333 + qemu_log_mask(LOG_GUEST_ERROR,
334 + "%s: Attempted to write to TX fifo when it is held in "
335 + "reset\n", DEVICE(s)->canonical_path);
336 + return;
337 + }
338 +
339 + /* Send the address if it hasn't been sent yet. */
340 + if (s->status == DW_I2C_STATUS_SENDING_ADDRESS) {
341 + int rv = i2c_start_transfer(s->bus,
342 + ARRAY_FIELD_EX32(s->regs, DW_IC_TAR, ADDRESS), recv);
343 + if (rv) {
344 + dw_ic_tx_abort(s, R_DW_IC_TX_ABRT_SOURCE_7B_ADDR_NOACK_MASK);
345 + return;
346 + }
347 + s->status = recv ? DW_I2C_STATUS_RECEIVING : DW_I2C_STATUS_SENDING;
348 + }
349 +
350 + /* Send data */
351 + if (!recv) {
352 + int rv = i2c_send(s->bus, FIELD_EX32(value, DW_IC_DATA_CMD, DAT));
353 + if (rv) {
354 + i2c_end_transfer(s->bus);
355 + dw_ic_tx_abort(s, R_DW_IC_TX_ABRT_SOURCE_TXDATA_NOACK_MASK);
356 + return;
357 + }
358 + dw_i2c_update_irq(s);
359 + }
360 +
361 + /* Restart command */
362 + if (value & R_DW_IC_DATA_CMD_RESTART_MASK &&
363 + s->regs[R_DW_IC_CON] & R_DW_IC_CON_IC_RESTART_EN_MASK) {
364 + s->regs[R_DW_IC_RAW_INTR_STAT] |= DW_IC_INTR_RESTART_DET_MASK |
365 + DW_IC_INTR_START_DET_MASK |
366 + DW_IC_INTR_ACTIVITY_MASK;
367 + s->regs[R_DW_IC_STATUS] |= R_DW_IC_STATUS_ACTIVITY_MASK;
368 + dw_i2c_update_irq(s);
369 +
370 + if (i2c_start_transfer(s->bus,
371 + ARRAY_FIELD_EX32(s->regs, DW_IC_TAR, ADDRESS), recv)) {
372 + dw_ic_tx_abort(s, R_DW_IC_TX_ABRT_SOURCE_7B_ADDR_NOACK_MASK);
373 + return;
374 + }
375 +
376 + s->status = recv ? DW_I2C_STATUS_RECEIVING : DW_I2C_STATUS_SENDING;
377 + }
378 +
379 + /* Receive data */
380 + if (recv) {
381 + g_assert(s->regs[R_DW_IC_RXFLR] == fifo8_num_used(&s->rx_fifo));
382 +
383 + if (!fifo8_is_full(&s->rx_fifo)) {
384 + fifo8_push(&s->rx_fifo, i2c_recv(s->bus));
385 + s->regs[R_DW_IC_RXFLR]++;
386 + } else {
387 + s->regs[R_DW_IC_RAW_INTR_STAT] |= DW_IC_INTR_RX_OVER_MASK;
388 + dw_i2c_update_irq(s);
389 + }
390 +
391 + if (s->regs[R_DW_IC_RXFLR] > s->regs[R_DW_IC_RX_TL]) {
392 + s->regs[R_DW_IC_RAW_INTR_STAT] |= DW_IC_INTR_RX_FULL_MASK;
393 + dw_i2c_update_irq(s);
394 + }
395 + if (value & R_DW_IC_DATA_CMD_STOP_MASK) {
396 + i2c_nack(s->bus);
397 + }
398 + }
399 +
400 + /* Stop command */
401 + if (value & R_DW_IC_DATA_CMD_STOP_MASK) {
402 + s->regs[R_DW_IC_RAW_INTR_STAT] |= DW_IC_INTR_STOP_DET_MASK;
403 + s->regs[R_DW_IC_STATUS] &= ~R_DW_IC_STATUS_ACTIVITY_MASK;
404 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_TX_EMPTY_MASK;
405 + i2c_end_transfer(s->bus);
406 + dw_i2c_update_irq(s);
407 + }
408 +}
409 +
410 +static void dw_ic_intr_mask_reg_post_write(RegisterInfo *reg, uint64_t value)
411 +{
412 + DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
413 +
414 + dw_i2c_update_irq(s);
415 +}
416 +
417 +static uint64_t dw_ic_enable_reg_pre_write(RegisterInfo *reg, uint64_t value)
418 +{
419 + DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
420 +
421 + if (value & R_DW_IC_ENABLE_ENABLE_MASK &&
422 + !(s->regs[R_DW_IC_CON] & R_DW_IC_CON_SLAVE_DISABLE_MASK)) {
423 + qemu_log_mask(LOG_UNIMP,
424 + "%s: Designware I2C slave mode is not supported.\n",
425 + DEVICE(s)->canonical_path);
426 + return s->regs[R_DW_IC_ENABLE]; /* keep old value */
427 + }
428 +
429 + return value;
430 +}
431 +
432 +static void dw_ic_enable_reg_post_write(RegisterInfo *reg, uint64_t value)
433 +{
434 + DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
435 +
436 + s->regs[R_DW_IC_ENABLE] = value & R_DW_IC_ENABLE_ENABLE_MASK;
437 +
438 + if (value & R_DW_IC_ENABLE_ABORT_MASK || value & R_DW_IC_ENABLE_TX_CMD_BLOCK_MASK) {
439 + dw_ic_tx_abort(s, R_DW_IC_TX_ABRT_SOURCE_USER_ABRT_MASK);
440 + return;
441 + }
442 +
443 + if (value & R_DW_IC_ENABLE_ENABLE_MASK) {
444 + s->regs[R_DW_IC_ENABLE_STATUS] |= R_DW_IC_ENABLE_STATUS_IC_EN_MASK;
445 + s->regs[R_DW_IC_STATUS] |= R_DW_IC_STATUS_ACTIVITY_MASK;
446 + s->regs[R_DW_IC_RAW_INTR_STAT] |= DW_IC_INTR_ACTIVITY_MASK |
447 + DW_IC_INTR_START_DET_MASK |
448 + DW_IC_INTR_TX_EMPTY_MASK;
449 + s->status = DW_I2C_STATUS_SENDING_ADDRESS;
450 + dw_i2c_update_irq(s);
451 + } else if ((value & R_DW_IC_ENABLE_ENABLE_MASK) == 0) {
452 + dw_i2c_reset_to_idle(s);
453 + }
454 +}
455 +
456 +static uint64_t dw_ic_rx_tl_reg_pre_write(RegisterInfo *reg, uint64_t value)
457 +{
458 + DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
459 +
460 + /* Note that a value of 0 for ic_rx_tl indicates a threshold of 1. */
461 + if (value > DESIGNWARE_I2C_RX_FIFO_SIZE - 1) {
462 + qemu_log_mask(LOG_GUEST_ERROR,
463 + "%s: invalid setting to ic_rx_tl %d\n",
464 + DEVICE(s)->canonical_path, (int)value);
465 + return DESIGNWARE_I2C_RX_FIFO_SIZE - 1;
466 + }
467 +
468 + return value;
469 +}
470 +
471 +static void dw_ic_rx_tl_reg_post_write(RegisterInfo *reg, uint64_t value)
472 +{
473 + DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
474 +
475 + if (s->regs[R_DW_IC_RXFLR] > s->regs[R_DW_IC_RX_TL] &&
476 + s->regs[R_DW_IC_ENABLE] & R_DW_IC_ENABLE_ENABLE_MASK) {
477 + s->regs[R_DW_IC_RAW_INTR_STAT] |= DW_IC_INTR_RX_FULL_MASK;
478 + } else {
479 + s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RX_FULL_MASK;
480 + }
481 + dw_i2c_update_irq(s);
482 +}
483 +
484 +static uint64_t dw_ic_tx_tl_reg_pre_write(RegisterInfo *reg, uint64_t value)
485 +{
486 + DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
487 +
488 + /*
489 + * Note that a value of 0 for ic_tx_tl indicates a threshold of 1.
490 + * However, the tx threshold is not used in the model because commands are
491 + * always sent out as soon as they are written.
492 + */
493 + if (value > DESIGNWARE_I2C_TX_FIFO_SIZE - 1) {
494 + qemu_log_mask(LOG_GUEST_ERROR,
495 + "%s: invalid setting to ic_tx_tl %d\n",
496 + DEVICE(s)->canonical_path, (int)value);
497 + return DESIGNWARE_I2C_TX_FIFO_SIZE - 1;
498 + }
499 +
500 + return value;
501 +}
502 +
503 +static const RegisterAccessInfo designware_i2c_regs_info[] = {
504 + { .name = "DW_IC_CON", .addr = A_DW_IC_CON,
505 + .reset = 0x7d,
506 + .unimp = 0xfffffc00,
507 + .pre_write = dw_ic_con_reg_pre_write,
508 + },{ .name = "DW_IC_TAR", .addr = A_DW_IC_TAR,
509 + .reset = 0x1055,
510 + .unimp = 0xfffff000,
511 + },{ .name = "DW_IC_SAR", .addr = A_DW_IC_SAR,
512 + .reset = 0x55,
513 + .unimp = 0xfffffc00,
514 + .post_read = dw_ic_unsupported_reg_post_read,
515 + .pre_write = dw_ic_unsupported_reg_pre_write,
516 + },{ .name = "DW_IC_DATA_CMD", .addr = A_DW_IC_DATA_CMD,
517 + .post_read = dw_ic_data_cmd_reg_post_read,
518 + .post_write = dw_ic_data_cmd_reg_post_write,
519 + },{ .name = "DW_IC_SS_SCL_HCNT", .addr = A_DW_IC_SS_SCL_HCNT,
520 + .reset = 0x190,
521 + .unimp = 0xffff0000,
522 + },{ .name = "DW_IC_SS_SCL_LCNT", .addr = A_DW_IC_SS_SCL_LCNT,
523 + .reset = 0x1d6,
524 + .unimp = 0xffff0000,
525 + },{ .name = "DW_IC_FS_SCL_HCNT", .addr = A_DW_IC_FS_SCL_HCNT,
526 + .reset = 0x3c,
527 + .unimp = 0xffff0000,
528 + },{ .name = "DW_IC_FS_SCL_LCNT", .addr = A_DW_IC_FS_SCL_LCNT,
529 + .reset = 0x82,
530 + .unimp = 0xffff0000,
531 + },{ .name = "DW_IC_INTR_STAT", .addr = A_DW_IC_INTR_STAT,
532 + .ro = 0xffffffff,
533 + .post_read = dw_ic_intr_stat_reg_post_read,
534 + },{ .name = "DW_IC_INTR_MASK", .addr = A_DW_IC_INTR_MASK,
535 + .reset = 0x8ff,
536 + .unimp = 0xffff8000,
537 + .post_write = dw_ic_intr_mask_reg_post_write,
538 + },{ .name = "DW_IC_RAW_INTR_STAT", .addr = A_DW_IC_RAW_INTR_STAT,
539 + .ro = 0xffffffff,
540 + },{ .name = "DW_IC_RX_TL", .addr = A_DW_IC_RX_TL,
541 + .pre_write = dw_ic_rx_tl_reg_pre_write,
542 + .post_write = dw_ic_rx_tl_reg_post_write,
543 + },{ .name = "DW_IC_TX_TL", .addr = A_DW_IC_TX_TL,
544 + .pre_write = dw_ic_tx_tl_reg_pre_write,
545 + },{ .name = "DW_IC_CLR_INTR", .addr = A_DW_IC_CLR_INTR,
546 + .ro = 0xffffffff,
547 + .post_read = dw_ic_clr_intr_reg_post_read,
548 + },{ .name = "DW_IC_CLR_RX_UNDER", .addr = A_DW_IC_CLR_RX_UNDER,
549 + .ro = 0xffffffff,
550 + .post_read = dw_ic_clr_intr_reg_post_read,
551 + },{ .name = "DW_IC_CLR_RX_OVER", .addr = A_DW_IC_CLR_RX_OVER,
552 + .ro = 0xffffffff,
553 + .post_read = dw_ic_clr_intr_reg_post_read,
554 + },{ .name = "DW_IC_CLR_TX_OVER", .addr = A_DW_IC_CLR_TX_OVER,
555 + .ro = 0xffffffff,
556 + .post_read = dw_ic_clr_intr_reg_post_read,
557 + },{ .name = "DW_IC_CLR_RD_REQ", .addr = A_DW_IC_CLR_RD_REQ,
558 + .ro = 0xffffffff,
559 + .post_read = dw_ic_clr_intr_reg_post_read,
560 + },{ .name = "DW_IC_CLR_TX_ABRT", .addr = A_DW_IC_CLR_TX_ABRT,
561 + .ro = 0xffffffff,
562 + .post_read = dw_ic_clr_intr_reg_post_read,
563 + },{ .name = "DW_IC_CLR_RX_DONE", .addr = A_DW_IC_CLR_RX_DONE,
564 + .ro = 0xffffffff,
565 + .post_read = dw_ic_clr_intr_reg_post_read,
566 + },{ .name = "DW_IC_CLR_ACTIVITY", .addr = A_DW_IC_CLR_ACTIVITY,
567 + .ro = 0xffffffff,
568 + .post_read = dw_ic_clr_intr_reg_post_read,
569 + },{ .name = "DW_IC_CLR_STOP_DET", .addr = A_DW_IC_CLR_STOP_DET,
570 + .ro = 0xffffffff,
571 + .post_read = dw_ic_clr_intr_reg_post_read,
572 + },{ .name = "DW_IC_CLR_START_DET", .addr = A_DW_IC_CLR_START_DET,
573 + .ro = 0xffffffff,
574 + .post_read = dw_ic_clr_intr_reg_post_read,
575 + },{ .name = "DW_IC_CLR_GEN_CALL", .addr = A_DW_IC_CLR_GEN_CALL,
576 + .ro = 0xffffffff,
577 + .post_read = dw_ic_clr_intr_reg_post_read,
578 + },{ .name = "DW_IC_ENABLE", .addr = A_DW_IC_ENABLE,
579 + .unimp = 0xfffffff8,
580 + .pre_write = dw_ic_enable_reg_pre_write,
581 + .post_write = dw_ic_enable_reg_post_write,
582 + },{ .name = "DW_IC_STATUS", .addr = A_DW_IC_STATUS,
583 + .reset = 0x6,
584 + .ro = 0xffffffff,
585 + },{ .name = "DW_IC_TXFLR", .addr = A_DW_IC_TXFLR,
586 + .ro = 0xffffffff,
587 + },{ .name = "DW_IC_RXFLR", .addr = A_DW_IC_RXFLR,
588 + .ro = 0xffffffff,
589 + },{ .name = "DW_IC_SDA_HOLD", .addr = A_DW_IC_SDA_HOLD,
590 + .reset = 0x1,
591 + .unimp = 0xff000000,
592 + },{ .name = "DW_IC_TX_ABRT_SOURCE", .addr = A_DW_IC_TX_ABRT_SOURCE,
593 + .ro = 0xffffffff,
594 + },{ .name = "DW_IC_SLV_DATA_NACK_ONLY", .addr = A_DW_IC_SLV_DATA_NACK_ONLY,
595 + .post_read = dw_ic_unsupported_reg_post_read,
596 + .pre_write = dw_ic_unsupported_reg_pre_write,
597 + },{ .name = "DW_IC_DMA_CR", .addr = A_DW_IC_DMA_CR,
598 + .post_read = dw_ic_unsupported_reg_post_read,
599 + .pre_write = dw_ic_unsupported_reg_pre_write,
600 + },{ .name = "DW_IC_DMA_TDLR", .addr = A_DW_IC_DMA_TDLR,
601 + .post_read = dw_ic_unsupported_reg_post_read,
602 + .pre_write = dw_ic_unsupported_reg_pre_write,
603 + },{ .name = "DW_IC_DMA_RDLR", .addr = A_DW_IC_DMA_RDLR,
604 + .post_read = dw_ic_unsupported_reg_post_read,
605 + .pre_write = dw_ic_unsupported_reg_pre_write,
606 + },{ .name = "DW_IC_SDA_SETUP", .addr = A_DW_IC_SDA_SETUP,
607 + .reset = 0x64,
608 + .unimp = 0xffffff00,
609 + },{ .name = "DW_IC_ACK_GENERAL_CALL", .addr = A_DW_IC_ACK_GENERAL_CALL,
610 + .post_read = dw_ic_unsupported_reg_post_read,
611 + .pre_write = dw_ic_unsupported_reg_pre_write,
612 + },{ .name = "DW_IC_ENABLE_STATUS", .addr = A_DW_IC_ENABLE_STATUS,
613 + .ro = 0xffffffff,
614 + },{ .name = "DW_IC_FS_SPKLEN", .addr = A_DW_IC_FS_SPKLEN,
615 + .reset = 0x2,
616 + .ro = 0xffffff00,
617 + },{ .name = "DW_IC_CLR_RESTART_DET", .addr = A_DW_IC_CLR_RESTART_DET,
618 + .ro = 0xffffffff,
619 + .post_read = dw_ic_clr_intr_reg_post_read,
620 + },{ .name = "DW_IC_SMBUS_INTR_MASK", .addr = A_DW_IC_SMBUS_INTR_MASK,
621 + /* No SMBus interrupts are implemented, Linux updates the mask */
622 + .reset = 0x7ff,
623 + .unimp = 0xfffff800,
624 + },{ .name = "DW_IC_COMP_PARAM_1", .addr = A_DW_IC_COMP_PARAM_1,
625 + .reset = /* HAS_DMA and HC_COUNT_VAL are disabled */
626 + ((2 << R_DW_IC_COMP_PARAM_1_APB_DATA_WIDTH_32_SHIFT) |
627 + R_DW_IC_COMP_PARAM_1_HIGH_SPEED_MODE_MASK |
628 + R_DW_IC_COMP_PARAM_1_INTR_IO_MASK |
629 + R_DW_IC_COMP_PARAM_1_HAS_ENCODED_PARAMS_MASK |
630 + ((DESIGNWARE_I2C_RX_FIFO_SIZE - 1)
631 + << R_DW_IC_COMP_PARAM_1_RX_FIFO_SIZE_SHIFT) |
632 + ((DESIGNWARE_I2C_TX_FIFO_SIZE - 1)
633 + << R_DW_IC_COMP_PARAM_1_TX_FIFO_SIZE_SHIFT)),
634 + .ro = 0xffffffff,
635 + },{ .name = "DW_IC_COMP_VERSION", .addr = A_DW_IC_COMP_VERSION,
636 + .reset = 0x3132302a,
637 + .ro = 0xffffffff,
638 + },{ .name = "DW_IC_COMP_TYPE", .addr = A_DW_IC_COMP_TYPE,
639 + .reset = 0x44570140,
640 + .ro = 0xffffffff,
641 + }
642 +};
643 +
644 +static const MemoryRegionOps designware_i2c_ops = {
645 + .read = register_read_memory,
646 + .write = register_write_memory,
647 + .endianness = DEVICE_LITTLE_ENDIAN,
648 + .impl = {
649 + .min_access_size = 4,
650 + .max_access_size = 4,
651 + },
652 + .valid = {
653 + .min_access_size = 4,
654 + .max_access_size = 4,
655 + .unaligned = false,
656 + },
657 +};
658 +
659 +static void designware_i2c_enter_reset(Object *obj, ResetType type)
660 +{
661 + DesignWareI2CState *s = DESIGNWARE_I2C(obj);
662 + unsigned int i;
663 +
664 + for (i = 0; i < ARRAY_SIZE(s->regs); ++i) {
665 + register_reset(&s->regs_info[i]);
666 + }
667 +
668 + fifo8_reset(&s->rx_fifo);
669 +
670 + s->status = DW_I2C_STATUS_IDLE;
671 +}
672 +
673 +static void designware_i2c_hold_reset(Object *obj, ResetType type)
674 +{
675 + DesignWareI2CState *s = DESIGNWARE_I2C(obj);
676 +
677 + qemu_irq_lower(s->irq);
678 +}
679 +
680 +static const VMStateDescription vmstate_designware_i2c = {
681 + .name = TYPE_DESIGNWARE_I2C,
682 + .version_id = 0,
683 + .minimum_version_id = 0,
684 + .fields = (const VMStateField[]) {
685 + VMSTATE_UINT32_ARRAY(regs, DesignWareI2CState, DESIGNWARE_I2C_R_MAX),
686 + VMSTATE_FIFO8(rx_fifo, DesignWareI2CState),
687 + VMSTATE_UINT32(status, DesignWareI2CState),
688 + VMSTATE_END_OF_LIST(),
689 + },
690 +};
691 +
692 +static void designware_i2c_instance_init(Object *obj)
693 +{
694 + DesignWareI2CState *s = DESIGNWARE_I2C(obj);
695 + SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
696 + RegisterInfoArray *reg_array;
697 +
698 + fifo8_create(&s->rx_fifo, DESIGNWARE_I2C_RX_FIFO_SIZE);
699 +
700 + s->bus = i2c_init_bus(DEVICE(s), "i2c-bus");
701 +
702 + memory_region_init(&s->iomem, obj, TYPE_DESIGNWARE_I2C, 4 * KiB);
703 + reg_array = register_init_block32(DEVICE(obj), designware_i2c_regs_info,
704 + ARRAY_SIZE(designware_i2c_regs_info),
705 + s->regs_info, s->regs,
706 + &designware_i2c_ops,
707 + DESIGNWARE_I2C_ERR_DEBUG,
708 + DESIGNWARE_I2C_R_MAX * 4);
709 + memory_region_add_subregion(&s->iomem, 0, &reg_array->mem);
710 +
711 + sysbus_init_mmio(sbd, &s->iomem);
712 + sysbus_init_irq(sbd, &s->irq);
713 +}
714 +
715 +static void designware_i2c_finalize(Object *obj)
716 +{
717 + DesignWareI2CState *s = DESIGNWARE_I2C(obj);
718 +
719 + fifo8_destroy(&s->rx_fifo);
720 +}
721 +
722 +static void designware_i2c_class_init(ObjectClass *klass, const void *data)
723 +{
724 + ResettableClass *rc = RESETTABLE_CLASS(klass);
725 + DeviceClass *dc = DEVICE_CLASS(klass);
726 +
727 + dc->desc = "Designware I2C";
728 + dc->vmsd = &vmstate_designware_i2c;
729 + rc->phases.enter = designware_i2c_enter_reset;
730 + rc->phases.hold = designware_i2c_hold_reset;
731 +
732 + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
733 +}
734 +
735 +static const TypeInfo designware_i2c_types[] = {
736 + {
737 + .name = TYPE_DESIGNWARE_I2C,
738 + .parent = TYPE_SYS_BUS_DEVICE,
739 + .instance_size = sizeof(DesignWareI2CState),
740 + .class_init = designware_i2c_class_init,
741 + .instance_init = designware_i2c_instance_init,
742 + .instance_finalize = designware_i2c_finalize,
743 + },
744 +};
745 +DEFINE_TYPES(designware_i2c_types);
hw/i2c/meson.build
+1
@@ -11,6 +11,7 @@ i2c_ss.add(when: 'CONFIG_MPC_I2C', if_true: files('mpc_i2c.c'))
11 i2c_ss.add(when: 'CONFIG_ALLWINNER_I2C', if_true: files('allwinner-i2c.c'))
12 i2c_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('microbit_i2c.c'))
13 i2c_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_smbus.c'))
14 +i2c_ss.add(when: 'CONFIG_DESIGNWARE_I2C', if_true: files('designware_i2c.c'))
15 i2c_ss.add(when: 'CONFIG_SMBUS_EEPROM', if_true: files('smbus_eeprom.c'))
16 i2c_ss.add(when: 'CONFIG_ARM_SBCON_I2C', if_true: files('arm_sbcon_i2c.c'))
17 i2c_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_i2c.c'))
include/hw/i2c/designware_i2c.h new
+56
@@ -0,0 +1,56 @@
1 +/*
2 + * DesignWare I2C Module.
3 + *
4 + * Copyright 2021 Google LLC
5 + *
6 + * SPDX-License-Identifier: GPL-2.0-or-later
7 + */
8 +#ifndef DESIGNWARE_I2C_H
9 +#define DESIGNWARE_I2C_H
10 +
11 +#include "qemu/fifo8.h"
12 +#include "hw/i2c/i2c.h"
13 +#include "hw/core/irq.h"
14 +#include "hw/core/register.h"
15 +#include "hw/core/sysbus.h"
16 +#include "qom/object.h"
17 +
18 +#define DESIGNWARE_I2C_R_MAX (0x100 / 4)
19 +
20 +#define DESIGNWARE_I2C_RX_FIFO_SIZE 16
21 +#define DESIGNWARE_I2C_TX_FIFO_SIZE 16
22 +
23 +typedef enum DesignWareI2CStatus {
24 + DW_I2C_STATUS_IDLE,
25 + DW_I2C_STATUS_SENDING_ADDRESS,
26 + DW_I2C_STATUS_SENDING,
27 + DW_I2C_STATUS_RECEIVING,
28 +} DesignWareI2CStatus;
29 +
30 +#define TYPE_DESIGNWARE_I2C "designware-i2c"
31 +OBJECT_DECLARE_SIMPLE_TYPE(DesignWareI2CState, DESIGNWARE_I2C)
32 +
33 +/*
34 + * struct DesignWareI2CState - DesignWare I2C device state.
35 + * @bus: The underlying I2C Bus
36 + * @irq: Interrupt line fired on transaction events.
37 + * @rx_fifo: The FIFO buffer for receiving in FIFO mode.
38 + */
39 +struct DesignWareI2CState {
40 + SysBusDevice parent_obj;
41 +
42 + MemoryRegion iomem;
43 +
44 + I2CBus *bus;
45 + qemu_irq irq;
46 +
47 + uint32_t regs[DESIGNWARE_I2C_R_MAX];
48 + RegisterInfo regs_info[DESIGNWARE_I2C_R_MAX];
49 +
50 + /* fifo8_num_used(rx_fifo) should always equal DW_IC_RXFLR */
51 + Fifo8 rx_fifo;
52 +
53 + DesignWareI2CStatus status;
54 +};
55 +
56 +#endif /* DESIGNWARE_I2C_H */