17d87775fSJoe Komlodi /*
27d87775fSJoe Komlodi * ASPEED I3C Controller
37d87775fSJoe Komlodi *
47d87775fSJoe Komlodi * Copyright (C) 2021 ASPEED Technology Inc.
5e7b1406cSJoe Komlodi * Copyright (C) 2023 Google LLC
67d87775fSJoe Komlodi *
77d87775fSJoe Komlodi * This code is licensed under the GPL version 2 or later. See
87d87775fSJoe Komlodi * the COPYING file in the top-level directory.
97d87775fSJoe Komlodi */
107d87775fSJoe Komlodi
117d87775fSJoe Komlodi #include "qemu/osdep.h"
127d87775fSJoe Komlodi #include "qemu/log.h"
137d87775fSJoe Komlodi #include "qemu/error-report.h"
147d87775fSJoe Komlodi #include "hw/i3c/aspeed_i3c.h"
157d87775fSJoe Komlodi #include "hw/registerfields.h"
167d87775fSJoe Komlodi #include "hw/qdev-properties.h"
177d87775fSJoe Komlodi #include "qapi/error.h"
187d87775fSJoe Komlodi #include "migration/vmstate.h"
197d87775fSJoe Komlodi #include "trace.h"
203816bedaSJoe Komlodi #include "hw/i3c/i3c.h"
213816bedaSJoe Komlodi #include "hw/irq.h"
227d87775fSJoe Komlodi
2393ec6949SJoe Komlodi /*
2493ec6949SJoe Komlodi * Disable event command values. sent along with a DISEC CCC to disable certain
2593ec6949SJoe Komlodi * events on targets.
2693ec6949SJoe Komlodi */
2793ec6949SJoe Komlodi #define DISEC_HJ 0x08
2893ec6949SJoe Komlodi #define DISEC_CR 0x02
2993ec6949SJoe Komlodi #define DISEC_INT 0x01
3093ec6949SJoe Komlodi
317d87775fSJoe Komlodi /* I3C Controller Registers */
327d87775fSJoe Komlodi REG32(I3C1_REG0, 0x10)
337d87775fSJoe Komlodi REG32(I3C1_REG1, 0x14)
347d87775fSJoe Komlodi FIELD(I3C1_REG1, I2C_MODE, 0, 1)
35e7b1406cSJoe Komlodi FIELD(I3C1_REG1, SLV_TEST_MODE, 1, 1)
36e7b1406cSJoe Komlodi FIELD(I3C1_REG1, ACT_MODE, 2, 2)
37e7b1406cSJoe Komlodi FIELD(I3C1_REG1, PENDING_INT, 4, 4)
38e7b1406cSJoe Komlodi FIELD(I3C1_REG1, SA, 8, 7)
397d87775fSJoe Komlodi FIELD(I3C1_REG1, SA_EN, 15, 1)
40e7b1406cSJoe Komlodi FIELD(I3C1_REG1, INST_ID, 16, 4)
417d87775fSJoe Komlodi REG32(I3C2_REG0, 0x20)
427d87775fSJoe Komlodi REG32(I3C2_REG1, 0x24)
437d87775fSJoe Komlodi FIELD(I3C2_REG1, I2C_MODE, 0, 1)
44e7b1406cSJoe Komlodi FIELD(I3C2_REG1, SLV_TEST_MODE, 1, 1)
45e7b1406cSJoe Komlodi FIELD(I3C2_REG1, ACT_MODE, 2, 2)
46e7b1406cSJoe Komlodi FIELD(I3C2_REG1, PENDING_INT, 4, 4)
47e7b1406cSJoe Komlodi FIELD(I3C2_REG1, SA, 8, 7)
487d87775fSJoe Komlodi FIELD(I3C2_REG1, SA_EN, 15, 1)
49e7b1406cSJoe Komlodi FIELD(I3C2_REG1, INST_ID, 16, 4)
507d87775fSJoe Komlodi REG32(I3C3_REG0, 0x30)
517d87775fSJoe Komlodi REG32(I3C3_REG1, 0x34)
527d87775fSJoe Komlodi FIELD(I3C3_REG1, I2C_MODE, 0, 1)
53e7b1406cSJoe Komlodi FIELD(I3C3_REG1, SLV_TEST_MODE, 1, 1)
54e7b1406cSJoe Komlodi FIELD(I3C3_REG1, ACT_MODE, 2, 2)
55e7b1406cSJoe Komlodi FIELD(I3C3_REG1, PENDING_INT, 4, 4)
56e7b1406cSJoe Komlodi FIELD(I3C3_REG1, SA, 8, 7)
577d87775fSJoe Komlodi FIELD(I3C3_REG1, SA_EN, 15, 1)
58e7b1406cSJoe Komlodi FIELD(I3C3_REG1, INST_ID, 16, 4)
597d87775fSJoe Komlodi REG32(I3C4_REG0, 0x40)
607d87775fSJoe Komlodi REG32(I3C4_REG1, 0x44)
617d87775fSJoe Komlodi FIELD(I3C4_REG1, I2C_MODE, 0, 1)
62e7b1406cSJoe Komlodi FIELD(I3C4_REG1, SLV_TEST_MODE, 1, 1)
63e7b1406cSJoe Komlodi FIELD(I3C4_REG1, ACT_MODE, 2, 2)
64e7b1406cSJoe Komlodi FIELD(I3C4_REG1, PENDING_INT, 4, 4)
65e7b1406cSJoe Komlodi FIELD(I3C4_REG1, SA, 8, 7)
667d87775fSJoe Komlodi FIELD(I3C4_REG1, SA_EN, 15, 1)
67e7b1406cSJoe Komlodi FIELD(I3C4_REG1, INST_ID, 16, 4)
687d87775fSJoe Komlodi REG32(I3C5_REG0, 0x50)
697d87775fSJoe Komlodi REG32(I3C5_REG1, 0x54)
707d87775fSJoe Komlodi FIELD(I3C5_REG1, I2C_MODE, 0, 1)
71e7b1406cSJoe Komlodi FIELD(I3C5_REG1, SLV_TEST_MODE, 1, 1)
72e7b1406cSJoe Komlodi FIELD(I3C5_REG1, ACT_MODE, 2, 2)
73e7b1406cSJoe Komlodi FIELD(I3C5_REG1, PENDING_INT, 4, 4)
74e7b1406cSJoe Komlodi FIELD(I3C5_REG1, SA, 8, 7)
757d87775fSJoe Komlodi FIELD(I3C5_REG1, SA_EN, 15, 1)
76e7b1406cSJoe Komlodi FIELD(I3C5_REG1, INST_ID, 16, 4)
777d87775fSJoe Komlodi REG32(I3C6_REG0, 0x60)
787d87775fSJoe Komlodi REG32(I3C6_REG1, 0x64)
797d87775fSJoe Komlodi FIELD(I3C6_REG1, I2C_MODE, 0, 1)
80e7b1406cSJoe Komlodi FIELD(I3C6_REG1, SLV_TEST_MODE, 1, 1)
81e7b1406cSJoe Komlodi FIELD(I3C6_REG1, ACT_MODE, 2, 2)
82e7b1406cSJoe Komlodi FIELD(I3C6_REG1, PENDING_INT, 4, 4)
83e7b1406cSJoe Komlodi FIELD(I3C6_REG1, SA, 8, 7)
847d87775fSJoe Komlodi FIELD(I3C6_REG1, SA_EN, 15, 1)
85e7b1406cSJoe Komlodi FIELD(I3C6_REG1, INST_ID, 16, 4)
867d87775fSJoe Komlodi
877d87775fSJoe Komlodi /* I3C Device Registers */
887d87775fSJoe Komlodi REG32(DEVICE_CTRL, 0x00)
89e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, I3C_BROADCAST_ADDR_INC, 0, 1)
90e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, I2C_SLAVE_PRESENT, 7, 1)
91e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, HOT_JOIN_ACK_NACK_CTRL, 8, 1)
92e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, IDLE_CNT_MULTIPLIER, 24, 2)
93e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, SLV_ADAPT_TO_I2C_I3C_MODE, 27, 1)
94e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, DMA_HANDSHAKE_EN, 28, 1)
95e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, I3C_ABORT, 29, 1)
96e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, I3C_RESUME, 30, 1)
97e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, I3C_EN, 31, 1)
987d87775fSJoe Komlodi REG32(DEVICE_ADDR, 0x04)
99e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR, STATIC_ADDR, 0, 7)
100e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR, STATIC_ADDR_VALID, 15, 1)
101e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR, DYNAMIC_ADDR, 16, 7)
102e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR, DYNAMIC_ADDR_VALID, 15, 1)
1037d87775fSJoe Komlodi REG32(HW_CAPABILITY, 0x08)
104e7b1406cSJoe Komlodi FIELD(HW_CAPABILITY, ENTDAA, 0, 1)
105e7b1406cSJoe Komlodi FIELD(HW_CAPABILITY, HDR_DDR, 3, 1)
106e7b1406cSJoe Komlodi FIELD(HW_CAPABILITY, HDR_TS, 4, 1)
1077d87775fSJoe Komlodi REG32(COMMAND_QUEUE_PORT, 0x0c)
108e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, CMD_ATTR, 0, 3)
109e7b1406cSJoe Komlodi /* Transfer command structure */
110e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, TID, 3, 4)
111e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, CMD, 7, 8)
112e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, CP, 15, 1)
113e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, DEV_INDEX, 16, 5)
114e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, SPEED, 21, 3)
115e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, ROC, 26, 1)
116e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, SDAP, 27, 1)
117e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, RNW, 28, 1)
118e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, TOC, 30, 1)
119e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, PEC, 31, 1)
120e7b1406cSJoe Komlodi /* Transfer argument data structure */
121e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, DB, 8, 8)
122e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, DL, 16, 16)
123e7b1406cSJoe Komlodi /* Short data argument data structure */
124e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, BYTE_STRB, 3, 3)
125e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, BYTE0, 8, 8)
126e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, BYTE1, 16, 8)
127e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, BYTE2, 24, 8)
128e7b1406cSJoe Komlodi /* Address assignment command structure */
129e7b1406cSJoe Komlodi /*
130e7b1406cSJoe Komlodi * bits 3..21 and 26..31 are the same as the transfer command structure, or
131e7b1406cSJoe Komlodi * marked as reserved.
132e7b1406cSJoe Komlodi */
133e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, DEV_COUNT, 21, 3)
1347d87775fSJoe Komlodi REG32(RESPONSE_QUEUE_PORT, 0x10)
135e7b1406cSJoe Komlodi FIELD(RESPONSE_QUEUE_PORT, DL, 0, 16)
136e7b1406cSJoe Komlodi FIELD(RESPONSE_QUEUE_PORT, CCCT, 16, 8)
137e7b1406cSJoe Komlodi FIELD(RESPONSE_QUEUE_PORT, TID, 24, 4)
138e7b1406cSJoe Komlodi FIELD(RESPONSE_QUEUE_PORT, ERR_STATUS, 28, 4)
1397d87775fSJoe Komlodi REG32(RX_TX_DATA_PORT, 0x14)
1407d87775fSJoe Komlodi REG32(IBI_QUEUE_STATUS, 0x18)
141e7b1406cSJoe Komlodi FIELD(IBI_QUEUE_STATUS, IBI_DATA_LEN, 0, 8)
142e7b1406cSJoe Komlodi FIELD(IBI_QUEUE_STATUS, IBI_ID, 8, 8)
143e7b1406cSJoe Komlodi FIELD(IBI_QUEUE_STATUS, LAST_STATUS, 24, 1)
144e7b1406cSJoe Komlodi FIELD(IBI_QUEUE_STATUS, ERROR, 30, 1)
145e7b1406cSJoe Komlodi FIELD(IBI_QUEUE_STATUS, IBI_STATUS, 31, 1)
1467d87775fSJoe Komlodi REG32(IBI_QUEUE_DATA, 0x18)
1477d87775fSJoe Komlodi REG32(QUEUE_THLD_CTRL, 0x1c)
148e7b1406cSJoe Komlodi FIELD(QUEUE_THLD_CTRL, CMD_BUF_EMPTY_THLD, 0, 8);
149e7b1406cSJoe Komlodi FIELD(QUEUE_THLD_CTRL, RESP_BUF_THLD, 8, 8);
150e7b1406cSJoe Komlodi FIELD(QUEUE_THLD_CTRL, IBI_DATA_THLD, 16, 8);
151e7b1406cSJoe Komlodi FIELD(QUEUE_THLD_CTRL, IBI_STATUS_THLD, 24, 8);
1527d87775fSJoe Komlodi REG32(DATA_BUFFER_THLD_CTRL, 0x20)
153e7b1406cSJoe Komlodi FIELD(DATA_BUFFER_THLD_CTRL, TX_BUF_THLD, 0, 3)
154e7b1406cSJoe Komlodi FIELD(DATA_BUFFER_THLD_CTRL, RX_BUF_THLD, 10, 3)
155e7b1406cSJoe Komlodi FIELD(DATA_BUFFER_THLD_CTRL, TX_START_THLD, 16, 3)
156e7b1406cSJoe Komlodi FIELD(DATA_BUFFER_THLD_CTRL, RX_START_THLD, 24, 3)
1577d87775fSJoe Komlodi REG32(IBI_QUEUE_CTRL, 0x24)
158e7b1406cSJoe Komlodi FIELD(IBI_QUEUE_CTRL, NOTIFY_REJECTED_HOT_JOIN, 0, 1)
159e7b1406cSJoe Komlodi FIELD(IBI_QUEUE_CTRL, NOTIFY_REJECTED_MASTER_REQ, 1, 1)
160e7b1406cSJoe Komlodi FIELD(IBI_QUEUE_CTRL, NOTIFY_REJECTED_SLAVE_IRQ, 3, 1)
1617d87775fSJoe Komlodi REG32(IBI_MR_REQ_REJECT, 0x2c)
1627d87775fSJoe Komlodi REG32(IBI_SIR_REQ_REJECT, 0x30)
1637d87775fSJoe Komlodi REG32(RESET_CTRL, 0x34)
164e7b1406cSJoe Komlodi FIELD(RESET_CTRL, CORE_RESET, 0, 1)
165e7b1406cSJoe Komlodi FIELD(RESET_CTRL, CMD_QUEUE_RESET, 1, 1)
166e7b1406cSJoe Komlodi FIELD(RESET_CTRL, RESP_QUEUE_RESET, 2, 1)
167e7b1406cSJoe Komlodi FIELD(RESET_CTRL, TX_BUF_RESET, 3, 1)
168e7b1406cSJoe Komlodi FIELD(RESET_CTRL, RX_BUF_RESET, 4, 1)
169e7b1406cSJoe Komlodi FIELD(RESET_CTRL, IBI_QUEUE_RESET, 5, 1)
1707d87775fSJoe Komlodi REG32(SLV_EVENT_CTRL, 0x38)
171e7b1406cSJoe Komlodi FIELD(SLV_EVENT_CTRL, SLV_INTERRUPT, 0, 1)
172e7b1406cSJoe Komlodi FIELD(SLV_EVENT_CTRL, MASTER_INTERRUPT, 1, 1)
173e7b1406cSJoe Komlodi FIELD(SLV_EVENT_CTRL, HOT_JOIN_INTERRUPT, 3, 1)
174e7b1406cSJoe Komlodi FIELD(SLV_EVENT_CTRL, ACTIVITY_STATE, 4, 2)
175e7b1406cSJoe Komlodi FIELD(SLV_EVENT_CTRL, MRL_UPDATED, 6, 1)
176e7b1406cSJoe Komlodi FIELD(SLV_EVENT_CTRL, MWL_UPDATED, 7, 1)
1777d87775fSJoe Komlodi REG32(INTR_STATUS, 0x3c)
178e7b1406cSJoe Komlodi FIELD(INTR_STATUS, TX_THLD, 0, 1)
179e7b1406cSJoe Komlodi FIELD(INTR_STATUS, RX_THLD, 1, 1)
180e7b1406cSJoe Komlodi FIELD(INTR_STATUS, IBI_THLD, 2, 1)
181e7b1406cSJoe Komlodi FIELD(INTR_STATUS, CMD_QUEUE_RDY, 3, 1)
182e7b1406cSJoe Komlodi FIELD(INTR_STATUS, RESP_RDY, 4, 1)
183e7b1406cSJoe Komlodi FIELD(INTR_STATUS, TRANSFER_ABORT, 5, 1)
184e7b1406cSJoe Komlodi FIELD(INTR_STATUS, CCC_UPDATED, 6, 1)
185e7b1406cSJoe Komlodi FIELD(INTR_STATUS, DYN_ADDR_ASSGN, 8, 1)
186e7b1406cSJoe Komlodi FIELD(INTR_STATUS, TRANSFER_ERR, 9, 1)
187e7b1406cSJoe Komlodi FIELD(INTR_STATUS, DEFSLV, 10, 1)
188e7b1406cSJoe Komlodi FIELD(INTR_STATUS, READ_REQ_RECV, 11, 1)
189e7b1406cSJoe Komlodi FIELD(INTR_STATUS, IBI_UPDATED, 12, 1)
190e7b1406cSJoe Komlodi FIELD(INTR_STATUS, BUSOWNER_UPDATED, 13, 1)
1917d87775fSJoe Komlodi REG32(INTR_STATUS_EN, 0x40)
192e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, TX_THLD, 0, 1)
193e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, RX_THLD, 1, 1)
194e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, IBI_THLD, 2, 1)
195e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, CMD_QUEUE_RDY, 3, 1)
196e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, RESP_RDY, 4, 1)
197e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, TRANSFER_ABORT, 5, 1)
198e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, CCC_UPDATED, 6, 1)
199e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, DYN_ADDR_ASSGN, 8, 1)
200e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, TRANSFER_ERR, 9, 1)
201e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, DEFSLV, 10, 1)
202e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, READ_REQ_RECV, 11, 1)
203e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, IBI_UPDATED, 12, 1)
204e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, BUSOWNER_UPDATED, 13, 1)
2057d87775fSJoe Komlodi REG32(INTR_SIGNAL_EN, 0x44)
206e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, TX_THLD, 0, 1)
207e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, RX_THLD, 1, 1)
208e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, IBI_THLD, 2, 1)
209e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, CMD_QUEUE_RDY, 3, 1)
210e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, RESP_RDY, 4, 1)
211e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, TRANSFER_ABORT, 5, 1)
212e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, CCC_UPDATED, 6, 1)
213e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, DYN_ADDR_ASSGN, 8, 1)
214e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, TRANSFER_ERR, 9, 1)
215e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, DEFSLV, 10, 1)
216e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, READ_REQ_RECV, 11, 1)
217e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, IBI_UPDATED, 12, 1)
218e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, BUSOWNER_UPDATED, 13, 1)
2197d87775fSJoe Komlodi REG32(INTR_FORCE, 0x48)
220e7b1406cSJoe Komlodi FIELD(INTR_FORCE, TX_THLD, 0, 1)
221e7b1406cSJoe Komlodi FIELD(INTR_FORCE, RX_THLD, 1, 1)
222e7b1406cSJoe Komlodi FIELD(INTR_FORCE, IBI_THLD, 2, 1)
223e7b1406cSJoe Komlodi FIELD(INTR_FORCE, CMD_QUEUE_RDY, 3, 1)
224e7b1406cSJoe Komlodi FIELD(INTR_FORCE, RESP_RDY, 4, 1)
225e7b1406cSJoe Komlodi FIELD(INTR_FORCE, TRANSFER_ABORT, 5, 1)
226e7b1406cSJoe Komlodi FIELD(INTR_FORCE, CCC_UPDATED, 6, 1)
227e7b1406cSJoe Komlodi FIELD(INTR_FORCE, DYN_ADDR_ASSGN, 8, 1)
228e7b1406cSJoe Komlodi FIELD(INTR_FORCE, TRANSFER_ERR, 9, 1)
229e7b1406cSJoe Komlodi FIELD(INTR_FORCE, DEFSLV, 10, 1)
230e7b1406cSJoe Komlodi FIELD(INTR_FORCE, READ_REQ_RECV, 11, 1)
231e7b1406cSJoe Komlodi FIELD(INTR_FORCE, IBI_UPDATED, 12, 1)
232e7b1406cSJoe Komlodi FIELD(INTR_FORCE, BUSOWNER_UPDATED, 13, 1)
2337d87775fSJoe Komlodi REG32(QUEUE_STATUS_LEVEL, 0x4c)
234e7b1406cSJoe Komlodi FIELD(QUEUE_STATUS_LEVEL, CMD_QUEUE_EMPTY_LOC, 0, 8)
235e7b1406cSJoe Komlodi FIELD(QUEUE_STATUS_LEVEL, RESP_BUF_BLR, 8, 8)
236e7b1406cSJoe Komlodi FIELD(QUEUE_STATUS_LEVEL, IBI_BUF_BLR, 16, 8)
237e7b1406cSJoe Komlodi FIELD(QUEUE_STATUS_LEVEL, IBI_STATUS_CNT, 24, 5)
2387d87775fSJoe Komlodi REG32(DATA_BUFFER_STATUS_LEVEL, 0x50)
239e7b1406cSJoe Komlodi FIELD(DATA_BUFFER_STATUS_LEVEL, TX_BUF_EMPTY_LOC, 0, 8)
240e7b1406cSJoe Komlodi FIELD(DATA_BUFFER_STATUS_LEVEL, RX_BUF_BLR, 16, 8)
2417d87775fSJoe Komlodi REG32(PRESENT_STATE, 0x54)
242e7b1406cSJoe Komlodi FIELD(PRESENT_STATE, SCL_LINE_SIGNAL_LEVEL, 0, 1)
243e7b1406cSJoe Komlodi FIELD(PRESENT_STATE, SDA_LINE_SIGNAL_LEVEL, 1, 1)
244e7b1406cSJoe Komlodi FIELD(PRESENT_STATE, CURRENT_MASTER, 2, 1)
245e7b1406cSJoe Komlodi FIELD(PRESENT_STATE, CM_TFR_STATUS, 8, 6)
246e7b1406cSJoe Komlodi FIELD(PRESENT_STATE, CM_TFR_ST_STATUS, 16, 6)
247e7b1406cSJoe Komlodi FIELD(PRESENT_STATE, CMD_TID, 24, 4)
2487d87775fSJoe Komlodi REG32(CCC_DEVICE_STATUS, 0x58)
249e7b1406cSJoe Komlodi FIELD(CCC_DEVICE_STATUS, PENDING_INTR, 0, 4)
250e7b1406cSJoe Komlodi FIELD(CCC_DEVICE_STATUS, PROTOCOL_ERR, 4, 2)
251e7b1406cSJoe Komlodi FIELD(CCC_DEVICE_STATUS, ACTIVITY_MODE, 6, 2)
252e7b1406cSJoe Komlodi FIELD(CCC_DEVICE_STATUS, UNDER_ERR, 8, 1)
253e7b1406cSJoe Komlodi FIELD(CCC_DEVICE_STATUS, SLV_BUSY, 9, 1)
254e7b1406cSJoe Komlodi FIELD(CCC_DEVICE_STATUS, OVERFLOW_ERR, 10, 1)
255e7b1406cSJoe Komlodi FIELD(CCC_DEVICE_STATUS, DATA_NOT_READY, 11, 1)
256e7b1406cSJoe Komlodi FIELD(CCC_DEVICE_STATUS, BUFFER_NOT_AVAIL, 12, 1)
2577d87775fSJoe Komlodi REG32(DEVICE_ADDR_TABLE_POINTER, 0x5c)
2587d87775fSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_POINTER, DEPTH, 16, 16)
2597d87775fSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_POINTER, ADDR, 0, 16)
2607d87775fSJoe Komlodi REG32(DEV_CHAR_TABLE_POINTER, 0x60)
261e7b1406cSJoe Komlodi FIELD(DEV_CHAR_TABLE_POINTER, P_DEV_CHAR_TABLE_START_ADDR, 0, 12)
262e7b1406cSJoe Komlodi FIELD(DEV_CHAR_TABLE_POINTER, DEV_CHAR_TABLE_DEPTH, 12, 7)
263e7b1406cSJoe Komlodi FIELD(DEV_CHAR_TABLE_POINTER, PRESENT_DEV_CHAR_TABLE_INDEX, 19, 3)
2647d87775fSJoe Komlodi REG32(VENDOR_SPECIFIC_REG_POINTER, 0x6c)
265e7b1406cSJoe Komlodi FIELD(VENDOR_SPECIFIC_REG_POINTER, P_VENDOR_REG_START_ADDR, 0, 16)
2667d87775fSJoe Komlodi REG32(SLV_MIPI_PID_VALUE, 0x70)
2677d87775fSJoe Komlodi REG32(SLV_PID_VALUE, 0x74)
268e7b1406cSJoe Komlodi FIELD(SLV_PID_VALUE, SLV_PID_DCR, 0, 12)
269e7b1406cSJoe Komlodi FIELD(SLV_PID_VALUE, SLV_INST_ID, 12, 4)
270e7b1406cSJoe Komlodi FIELD(SLV_PID_VALUE, SLV_PART_ID, 16, 16)
2717d87775fSJoe Komlodi REG32(SLV_CHAR_CTRL, 0x78)
272e7b1406cSJoe Komlodi FIELD(SLV_CHAR_CTRL, BCR, 0, 8)
273e7b1406cSJoe Komlodi FIELD(SLV_CHAR_CTRL, DCR, 8, 8)
274e7b1406cSJoe Komlodi FIELD(SLV_CHAR_CTRL, HDR_CAP, 16, 8)
2757d87775fSJoe Komlodi REG32(SLV_MAX_LEN, 0x7c)
276e7b1406cSJoe Komlodi FIELD(SLV_MAX_LEN, MWL, 0, 16)
277e7b1406cSJoe Komlodi FIELD(SLV_MAX_LEN, MRL, 16, 16)
2787d87775fSJoe Komlodi REG32(MAX_READ_TURNAROUND, 0x80)
2797d87775fSJoe Komlodi REG32(MAX_DATA_SPEED, 0x84)
2807d87775fSJoe Komlodi REG32(SLV_DEBUG_STATUS, 0x88)
2817d87775fSJoe Komlodi REG32(SLV_INTR_REQ, 0x8c)
282e7b1406cSJoe Komlodi FIELD(SLV_INTR_REQ, SIR, 0, 1)
283e7b1406cSJoe Komlodi FIELD(SLV_INTR_REQ, SIR_CTRL, 1, 2)
284e7b1406cSJoe Komlodi FIELD(SLV_INTR_REQ, MIR, 3, 1)
285e7b1406cSJoe Komlodi FIELD(SLV_INTR_REQ, IBI_STS, 8, 2)
286e7b1406cSJoe Komlodi REG32(SLV_TSX_SYMBL_TIMING, 0x90)
287e7b1406cSJoe Komlodi FIELD(SLV_TSX_SYMBL_TIMING, SLV_TSX_SYMBL_CNT, 0, 6)
2887d87775fSJoe Komlodi REG32(DEVICE_CTRL_EXTENDED, 0xb0)
289e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL_EXTENDED, MODE, 0, 2)
290e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL_EXTENDED, REQMST_ACK_CTRL, 3, 1)
2917d87775fSJoe Komlodi REG32(SCL_I3C_OD_TIMING, 0xb4)
292e7b1406cSJoe Komlodi FIELD(SCL_I3C_OD_TIMING, I3C_OD_LCNT, 0, 8)
293e7b1406cSJoe Komlodi FIELD(SCL_I3C_OD_TIMING, I3C_OD_HCNT, 16, 8)
2947d87775fSJoe Komlodi REG32(SCL_I3C_PP_TIMING, 0xb8)
295e7b1406cSJoe Komlodi FIELD(SCL_I3C_PP_TIMING, I3C_PP_LCNT, 0, 8)
296e7b1406cSJoe Komlodi FIELD(SCL_I3C_PP_TIMING, I3C_PP_HCNT, 16, 8)
2977d87775fSJoe Komlodi REG32(SCL_I2C_FM_TIMING, 0xbc)
2987d87775fSJoe Komlodi REG32(SCL_I2C_FMP_TIMING, 0xc0)
299e7b1406cSJoe Komlodi FIELD(SCL_I2C_FMP_TIMING, I2C_FMP_LCNT, 0, 16)
300e7b1406cSJoe Komlodi FIELD(SCL_I2C_FMP_TIMING, I2C_FMP_HCNT, 16, 8)
3017d87775fSJoe Komlodi REG32(SCL_EXT_LCNT_TIMING, 0xc8)
3027d87775fSJoe Komlodi REG32(SCL_EXT_TERMN_LCNT_TIMING, 0xcc)
3037d87775fSJoe Komlodi REG32(BUS_FREE_TIMING, 0xd4)
3047d87775fSJoe Komlodi REG32(BUS_IDLE_TIMING, 0xd8)
305e7b1406cSJoe Komlodi FIELD(BUS_IDLE_TIMING, BUS_IDLE_TIME, 0, 20)
3067d87775fSJoe Komlodi REG32(I3C_VER_ID, 0xe0)
3077d87775fSJoe Komlodi REG32(I3C_VER_TYPE, 0xe4)
3087d87775fSJoe Komlodi REG32(EXTENDED_CAPABILITY, 0xe8)
309e7b1406cSJoe Komlodi FIELD(EXTENDED_CAPABILITY, APP_IF_MODE, 0, 2)
310e7b1406cSJoe Komlodi FIELD(EXTENDED_CAPABILITY, APP_IF_DATA_WIDTH, 2, 2)
311e7b1406cSJoe Komlodi FIELD(EXTENDED_CAPABILITY, OPERATION_MODE, 4, 2)
312e7b1406cSJoe Komlodi FIELD(EXTENDED_CAPABILITY, CLK_PERIOD, 8, 6)
3137d87775fSJoe Komlodi REG32(SLAVE_CONFIG, 0xec)
314e7b1406cSJoe Komlodi FIELD(SLAVE_CONFIG, DMA_EN, 0, 1)
315e7b1406cSJoe Komlodi FIELD(SLAVE_CONFIG, HJ_CAP, 0, 1)
316e7b1406cSJoe Komlodi FIELD(SLAVE_CONFIG, CLK_PERIOD, 2, 14)
317e7b1406cSJoe Komlodi /* Device characteristic table fields */
318e7b1406cSJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC1, 0x200)
319e7b1406cSJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, 0x200)
320e7b1406cSJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, DYNAMIC_ADDR, 0, 8)
321e7b1406cSJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, DCR, 8, 8)
322e7b1406cSJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, BCR, 16, 8)
323e7b1406cSJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, STATIC_ADDR, 24, 8)
324e7b1406cSJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC2, 0x204)
325e7b1406cSJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC2, MSB_PID, 0, 16)
326e7b1406cSJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC3, 0x208)
327e7b1406cSJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC3, DCR, 0, 8)
328e7b1406cSJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC3, BCR, 8, 8)
329e7b1406cSJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC4, 0x20c)
330e7b1406cSJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC4, DEV_DYNAMIC_ADDR, 0, 8)
331e7b1406cSJoe Komlodi /* Dev addr table fields */
332e7b1406cSJoe Komlodi REG32(DEVICE_ADDR_TABLE_LOC1, 0x280)
333e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, DEV_STATIC_ADDR, 0, 7)
334e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, IBI_PEC_EN, 11, 1)
335e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, IBI_WITH_DATA, 12, 1)
336e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, SIR_REJECT, 13, 1)
337e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, MR_REJECT, 14, 1)
338e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, DEV_DYNAMIC_ADDR, 16, 8)
339e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, IBI_ADDR_MASK, 24, 2)
340e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, DEV_NACK_RETRY_CNT, 29, 2)
341e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, LEGACY_I2C_DEVICE, 31, 1)
3427d87775fSJoe Komlodi
343eee51e8fSJoe Komlodi static void aspeed_i3c_device_cmd_queue_execute(AspeedI3CDevice *s);
344eee51e8fSJoe Komlodi
345a9d3f922SJoe Komlodi static const uint32_t ast2600_i3c_controller_ro[ASPEED_I3C_DEVICE_NR_REGS] = {
346a9d3f922SJoe Komlodi [R_I3C1_REG0] = 0xfc000000,
347a9d3f922SJoe Komlodi [R_I3C1_REG1] = 0xfff00000,
348a9d3f922SJoe Komlodi [R_I3C2_REG0] = 0xfc000000,
349a9d3f922SJoe Komlodi [R_I3C2_REG1] = 0xfff00000,
350a9d3f922SJoe Komlodi [R_I3C3_REG0] = 0xfc000000,
351a9d3f922SJoe Komlodi [R_I3C3_REG1] = 0xfff00000,
352a9d3f922SJoe Komlodi [R_I3C4_REG0] = 0xfc000000,
353a9d3f922SJoe Komlodi [R_I3C4_REG1] = 0xfff00000,
354a9d3f922SJoe Komlodi [R_I3C5_REG0] = 0xfc000000,
355a9d3f922SJoe Komlodi [R_I3C5_REG1] = 0xfff00000,
356a9d3f922SJoe Komlodi [R_I3C6_REG0] = 0xfc000000,
357a9d3f922SJoe Komlodi [R_I3C6_REG1] = 0xfff00000,
358a9d3f922SJoe Komlodi };
359a9d3f922SJoe Komlodi
3607d87775fSJoe Komlodi static const uint32_t ast2600_i3c_device_resets[ASPEED_I3C_DEVICE_NR_REGS] = {
3617d87775fSJoe Komlodi [R_HW_CAPABILITY] = 0x000e00bf,
3627d87775fSJoe Komlodi [R_QUEUE_THLD_CTRL] = 0x01000101,
3631032d6d6SJoe Komlodi [R_DATA_BUFFER_THLD_CTRL] = 0x01010100,
3641032d6d6SJoe Komlodi [R_SLV_EVENT_CTRL] = 0x0000000b,
3651032d6d6SJoe Komlodi [R_QUEUE_STATUS_LEVEL] = 0x00000002,
3661032d6d6SJoe Komlodi [R_DATA_BUFFER_STATUS_LEVEL] = 0x00000010,
3671032d6d6SJoe Komlodi [R_PRESENT_STATE] = 0x00000003,
3687d87775fSJoe Komlodi [R_I3C_VER_ID] = 0x3130302a,
3697d87775fSJoe Komlodi [R_I3C_VER_TYPE] = 0x6c633033,
3707d87775fSJoe Komlodi [R_DEVICE_ADDR_TABLE_POINTER] = 0x00080280,
3717d87775fSJoe Komlodi [R_DEV_CHAR_TABLE_POINTER] = 0x00020200,
3721032d6d6SJoe Komlodi [R_SLV_CHAR_CTRL] = 0x00010000,
3737d87775fSJoe Komlodi [A_VENDOR_SPECIFIC_REG_POINTER] = 0x000000b0,
3747d87775fSJoe Komlodi [R_SLV_MAX_LEN] = 0x00ff00ff,
3751032d6d6SJoe Komlodi [R_SLV_TSX_SYMBL_TIMING] = 0x0000003f,
3761032d6d6SJoe Komlodi [R_SCL_I3C_OD_TIMING] = 0x000a0010,
3771032d6d6SJoe Komlodi [R_SCL_I3C_PP_TIMING] = 0x000a000a,
3781032d6d6SJoe Komlodi [R_SCL_I2C_FM_TIMING] = 0x00100010,
3791032d6d6SJoe Komlodi [R_SCL_I2C_FMP_TIMING] = 0x00100010,
3801032d6d6SJoe Komlodi [R_SCL_EXT_LCNT_TIMING] = 0x20202020,
3811032d6d6SJoe Komlodi [R_SCL_EXT_TERMN_LCNT_TIMING] = 0x00300000,
3821032d6d6SJoe Komlodi [R_BUS_FREE_TIMING] = 0x00200020,
3831032d6d6SJoe Komlodi [R_BUS_IDLE_TIMING] = 0x00000020,
3841032d6d6SJoe Komlodi [R_EXTENDED_CAPABILITY] = 0x00000239,
3851032d6d6SJoe Komlodi [R_SLAVE_CONFIG] = 0x00000023,
3867d87775fSJoe Komlodi };
3877d87775fSJoe Komlodi
388a9d3f922SJoe Komlodi static const uint32_t ast2600_i3c_device_ro[ASPEED_I3C_DEVICE_NR_REGS] = {
389a9d3f922SJoe Komlodi [R_DEVICE_CTRL] = 0x04fffe00,
390a9d3f922SJoe Komlodi [R_DEVICE_ADDR] = 0x7f807f80,
391a9d3f922SJoe Komlodi [R_HW_CAPABILITY] = 0xffffffff,
392a9d3f922SJoe Komlodi [R_IBI_QUEUE_STATUS] = 0xffffffff,
393a9d3f922SJoe Komlodi [R_DATA_BUFFER_THLD_CTRL] = 0xf8f8f8f8,
394a9d3f922SJoe Komlodi [R_IBI_QUEUE_CTRL] = 0xfffffff0,
395a9d3f922SJoe Komlodi [R_RESET_CTRL] = 0xffffffc0,
396a9d3f922SJoe Komlodi [R_SLV_EVENT_CTRL] = 0xffffff3f,
397a9d3f922SJoe Komlodi [R_INTR_STATUS] = 0xffff809f,
398a9d3f922SJoe Komlodi [R_INTR_STATUS_EN] = 0xffff8080,
399a9d3f922SJoe Komlodi [R_INTR_SIGNAL_EN] = 0xffff8080,
400a9d3f922SJoe Komlodi [R_INTR_FORCE] = 0xffff8000,
401a9d3f922SJoe Komlodi [R_QUEUE_STATUS_LEVEL] = 0xffffffff,
402a9d3f922SJoe Komlodi [R_DATA_BUFFER_STATUS_LEVEL] = 0xffffffff,
403a9d3f922SJoe Komlodi [R_PRESENT_STATE] = 0xffffffff,
404a9d3f922SJoe Komlodi [R_CCC_DEVICE_STATUS] = 0xffffffff,
405a9d3f922SJoe Komlodi [R_I3C_VER_ID] = 0xffffffff,
406a9d3f922SJoe Komlodi [R_I3C_VER_TYPE] = 0xffffffff,
407a9d3f922SJoe Komlodi [R_DEVICE_ADDR_TABLE_POINTER] = 0xffffffff,
408a9d3f922SJoe Komlodi [R_DEV_CHAR_TABLE_POINTER] = 0xffcbffff,
409a9d3f922SJoe Komlodi [R_SLV_PID_VALUE] = 0xffff0fff,
410a9d3f922SJoe Komlodi [R_SLV_CHAR_CTRL] = 0xffffffff,
411a9d3f922SJoe Komlodi [A_VENDOR_SPECIFIC_REG_POINTER] = 0xffffffff,
412a9d3f922SJoe Komlodi [R_SLV_MAX_LEN] = 0xffffffff,
413a9d3f922SJoe Komlodi [R_MAX_READ_TURNAROUND] = 0xffffffff,
414a9d3f922SJoe Komlodi [R_MAX_DATA_SPEED] = 0xffffffff,
415a9d3f922SJoe Komlodi [R_SLV_INTR_REQ] = 0xfffffff0,
416a9d3f922SJoe Komlodi [R_SLV_TSX_SYMBL_TIMING] = 0xffffffc0,
417a9d3f922SJoe Komlodi [R_DEVICE_CTRL_EXTENDED] = 0xfffffff8,
418a9d3f922SJoe Komlodi [R_SCL_I3C_OD_TIMING] = 0xff00ff00,
419a9d3f922SJoe Komlodi [R_SCL_I3C_PP_TIMING] = 0xff00ff00,
420a9d3f922SJoe Komlodi [R_SCL_I2C_FMP_TIMING] = 0xff000000,
421a9d3f922SJoe Komlodi [R_SCL_EXT_TERMN_LCNT_TIMING] = 0x0000fff0,
422a9d3f922SJoe Komlodi [R_BUS_IDLE_TIMING] = 0xfff00000,
423a9d3f922SJoe Komlodi [R_EXTENDED_CAPABILITY] = 0xffffffff,
424a9d3f922SJoe Komlodi [R_SLAVE_CONFIG] = 0xffffffff,
425a9d3f922SJoe Komlodi };
426a9d3f922SJoe Komlodi
aspeed_i3c_device_has_entdaa(AspeedI3CDevice * s)4274ba25376SJoe Komlodi static inline bool aspeed_i3c_device_has_entdaa(AspeedI3CDevice *s)
4284ba25376SJoe Komlodi {
4294ba25376SJoe Komlodi return ARRAY_FIELD_EX32(s->regs, HW_CAPABILITY, ENTDAA);
4304ba25376SJoe Komlodi }
4314ba25376SJoe Komlodi
aspeed_i3c_device_has_hdr_ts(AspeedI3CDevice * s)4324ba25376SJoe Komlodi static inline bool aspeed_i3c_device_has_hdr_ts(AspeedI3CDevice *s)
4334ba25376SJoe Komlodi {
4344ba25376SJoe Komlodi return ARRAY_FIELD_EX32(s->regs, HW_CAPABILITY, HDR_TS);
4354ba25376SJoe Komlodi }
4364ba25376SJoe Komlodi
aspeed_i3c_device_has_hdr_ddr(AspeedI3CDevice * s)4374ba25376SJoe Komlodi static inline bool aspeed_i3c_device_has_hdr_ddr(AspeedI3CDevice *s)
4384ba25376SJoe Komlodi {
4394ba25376SJoe Komlodi return ARRAY_FIELD_EX32(s->regs, HW_CAPABILITY, HDR_DDR);
4404ba25376SJoe Komlodi }
4414ba25376SJoe Komlodi
aspeed_i3c_device_can_transmit(AspeedI3CDevice * s)4424ba25376SJoe Komlodi static inline bool aspeed_i3c_device_can_transmit(AspeedI3CDevice *s)
4434ba25376SJoe Komlodi {
4444ba25376SJoe Komlodi /*
4454ba25376SJoe Komlodi * We can only transmit if we're enabled and the resume bit is cleared.
4464ba25376SJoe Komlodi * The resume bit is set on a transaction error, and software must clear it.
4474ba25376SJoe Komlodi */
4484ba25376SJoe Komlodi return ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL, I3C_EN) &&
4494ba25376SJoe Komlodi !ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL, I3C_RESUME);
4504ba25376SJoe Komlodi }
4514ba25376SJoe Komlodi
aspeed_i3c_device_fifo_threshold_from_reg(uint8_t regval)4524ba25376SJoe Komlodi static inline uint8_t aspeed_i3c_device_fifo_threshold_from_reg(uint8_t regval)
4534ba25376SJoe Komlodi {
4544ba25376SJoe Komlodi return regval = regval ? (2 << regval) : 1;
4554ba25376SJoe Komlodi }
4564ba25376SJoe Komlodi
aspeed_i3c_device_ibi_slice_size(AspeedI3CDevice * s)45793ec6949SJoe Komlodi static inline uint8_t aspeed_i3c_device_ibi_slice_size(AspeedI3CDevice *s)
45893ec6949SJoe Komlodi {
45993ec6949SJoe Komlodi uint8_t ibi_slice_size = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL,
46093ec6949SJoe Komlodi IBI_DATA_THLD);
46193ec6949SJoe Komlodi /* The minimum supported slice size is 4 bytes. */
46293ec6949SJoe Komlodi if (ibi_slice_size == 0) {
46393ec6949SJoe Komlodi ibi_slice_size = 1;
46493ec6949SJoe Komlodi }
46593ec6949SJoe Komlodi ibi_slice_size *= sizeof(uint32_t);
46693ec6949SJoe Komlodi /* maximum supported size is 63 bytes. */
46793ec6949SJoe Komlodi if (ibi_slice_size >= 64) {
46893ec6949SJoe Komlodi ibi_slice_size = 63;
46993ec6949SJoe Komlodi }
47093ec6949SJoe Komlodi
47193ec6949SJoe Komlodi return ibi_slice_size;
47293ec6949SJoe Komlodi }
47393ec6949SJoe Komlodi
aspeed_i3c_device_update_irq(AspeedI3CDevice * s)4743816bedaSJoe Komlodi static void aspeed_i3c_device_update_irq(AspeedI3CDevice *s)
4753816bedaSJoe Komlodi {
4763816bedaSJoe Komlodi bool level = !!(s->regs[R_INTR_SIGNAL_EN] & s->regs[R_INTR_STATUS]);
4773816bedaSJoe Komlodi qemu_set_irq(s->irq, level);
4783816bedaSJoe Komlodi }
4793816bedaSJoe Komlodi
aspeed_i3c_device_end_transfer(AspeedI3CDevice * s,bool is_i2c)4804ba25376SJoe Komlodi static void aspeed_i3c_device_end_transfer(AspeedI3CDevice *s, bool is_i2c)
4814ba25376SJoe Komlodi {
4824ba25376SJoe Komlodi if (is_i2c) {
4834ba25376SJoe Komlodi legacy_i2c_end_transfer(s->bus);
4844ba25376SJoe Komlodi } else {
4854ba25376SJoe Komlodi i3c_end_transfer(s->bus);
4864ba25376SJoe Komlodi }
4874ba25376SJoe Komlodi }
4884ba25376SJoe Komlodi
aspeed_i3c_device_send_start(AspeedI3CDevice * s,uint8_t addr,bool is_recv,bool is_i2c)4894ba25376SJoe Komlodi static int aspeed_i3c_device_send_start(AspeedI3CDevice *s, uint8_t addr,
4904ba25376SJoe Komlodi bool is_recv, bool is_i2c)
4914ba25376SJoe Komlodi {
4924ba25376SJoe Komlodi int ret;
4934ba25376SJoe Komlodi
4944ba25376SJoe Komlodi if (is_i2c) {
4954ba25376SJoe Komlodi ret = legacy_i2c_start_transfer(s->bus, addr, is_recv);
4964ba25376SJoe Komlodi } else {
4974ba25376SJoe Komlodi ret = i3c_start_transfer(s->bus, addr, is_recv);
4984ba25376SJoe Komlodi }
4994ba25376SJoe Komlodi if (ret) {
5004ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: NACKed on TX with addr 0x%.2x\n",
5014ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s)), addr);
5024ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS,
5034ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_HALT);
5044ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS,
5054ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATUS_HALT);
5064ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TRANSFER_ERR, 1);
5074ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEVICE_CTRL, I3C_RESUME, 1);
5084ba25376SJoe Komlodi }
5094ba25376SJoe Komlodi
5104ba25376SJoe Komlodi return ret;
5114ba25376SJoe Komlodi }
5124ba25376SJoe Komlodi
aspeed_i3c_device_send(AspeedI3CDevice * s,const uint8_t * data,uint32_t num_to_send,uint32_t * num_sent,bool is_i2c)5134ba25376SJoe Komlodi static int aspeed_i3c_device_send(AspeedI3CDevice *s, const uint8_t *data,
5144ba25376SJoe Komlodi uint32_t num_to_send, uint32_t *num_sent,
5154ba25376SJoe Komlodi bool is_i2c)
5164ba25376SJoe Komlodi {
5174ba25376SJoe Komlodi int ret;
5184ba25376SJoe Komlodi uint32_t i;
5194ba25376SJoe Komlodi
5204ba25376SJoe Komlodi *num_sent = 0;
5214ba25376SJoe Komlodi if (is_i2c) {
5224ba25376SJoe Komlodi /* Legacy I2C must be byte-by-byte. */
5234ba25376SJoe Komlodi for (i = 0; i < num_to_send; i++) {
5244ba25376SJoe Komlodi ret = legacy_i2c_send(s->bus, data[i]);
5254ba25376SJoe Komlodi if (ret) {
5264ba25376SJoe Komlodi break;
5274ba25376SJoe Komlodi }
5284ba25376SJoe Komlodi (*num_sent)++;
5294ba25376SJoe Komlodi }
5304ba25376SJoe Komlodi } else {
5314ba25376SJoe Komlodi ret = i3c_send(s->bus, data, num_to_send, num_sent);
5324ba25376SJoe Komlodi }
5334ba25376SJoe Komlodi if (ret) {
5344ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: NACKed sending byte 0x%.2x\n",
5354ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s)), data[*num_sent]);
5364ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS,
5374ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_HALT);
5384ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS,
5394ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATUS_HALT);
5404ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TRANSFER_ERR, 1);
5414ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEVICE_CTRL, I3C_RESUME, 1);
5424ba25376SJoe Komlodi }
5434ba25376SJoe Komlodi
5444ba25376SJoe Komlodi trace_aspeed_i3c_device_send(s->id, *num_sent);
5454ba25376SJoe Komlodi
5464ba25376SJoe Komlodi return ret;
5474ba25376SJoe Komlodi }
5484ba25376SJoe Komlodi
aspeed_i3c_device_send_byte(AspeedI3CDevice * s,uint8_t byte,bool is_i2c)5494ba25376SJoe Komlodi static int aspeed_i3c_device_send_byte(AspeedI3CDevice *s, uint8_t byte,
5504ba25376SJoe Komlodi bool is_i2c)
5514ba25376SJoe Komlodi {
5524ba25376SJoe Komlodi /*
5534ba25376SJoe Komlodi * Ignored, the caller will know if we sent 0 or 1 bytes depending on if
5544ba25376SJoe Komlodi * we were ACKed/NACKed.
5554ba25376SJoe Komlodi */
5564ba25376SJoe Komlodi uint32_t num_sent;
5574ba25376SJoe Komlodi return aspeed_i3c_device_send(s, &byte, 1, &num_sent, is_i2c);
5584ba25376SJoe Komlodi }
5594ba25376SJoe Komlodi
aspeed_i3c_device_recv_data(AspeedI3CDevice * s,bool is_i2c,uint8_t * data,uint16_t num_to_read,uint32_t * num_read)5604ba25376SJoe Komlodi static int aspeed_i3c_device_recv_data(AspeedI3CDevice *s, bool is_i2c,
5614ba25376SJoe Komlodi uint8_t *data, uint16_t num_to_read,
5624ba25376SJoe Komlodi uint32_t *num_read)
5634ba25376SJoe Komlodi {
5644ba25376SJoe Komlodi int ret;
5654ba25376SJoe Komlodi
5664ba25376SJoe Komlodi if (is_i2c) {
5674ba25376SJoe Komlodi for (uint16_t i = 0; i < num_to_read; i++) {
5684ba25376SJoe Komlodi data[i] = legacy_i2c_recv(s->bus);
5694ba25376SJoe Komlodi }
5704ba25376SJoe Komlodi /* I2C devices can neither NACK a read, nor end transfers early. */
5714ba25376SJoe Komlodi *num_read = num_to_read;
5724ba25376SJoe Komlodi trace_aspeed_i3c_device_recv_data(s->id, *num_read);
5734ba25376SJoe Komlodi return 0;
5744ba25376SJoe Komlodi }
5754ba25376SJoe Komlodi /* I3C devices can NACK if the controller sends an unsupported CCC. */
5764ba25376SJoe Komlodi ret = i3c_recv(s->bus, data, num_to_read, num_read);
5774ba25376SJoe Komlodi if (ret) {
5784ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: NACKed receiving byte\n",
5794ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s)));
5804ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS,
5814ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_HALT);
5824ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS,
5834ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATUS_HALT);
5844ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TRANSFER_ERR, 1);
5854ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEVICE_CTRL, I3C_RESUME, 1);
5864ba25376SJoe Komlodi }
5874ba25376SJoe Komlodi
5884ba25376SJoe Komlodi trace_aspeed_i3c_device_recv_data(s->id, *num_read);
5894ba25376SJoe Komlodi
5904ba25376SJoe Komlodi return ret;
5914ba25376SJoe Komlodi }
5924ba25376SJoe Komlodi
aspeed_i3c_device_ctrl_w(AspeedI3CDevice * s,uint32_t val)593eee51e8fSJoe Komlodi static inline void aspeed_i3c_device_ctrl_w(AspeedI3CDevice *s,
594eee51e8fSJoe Komlodi uint32_t val)
595eee51e8fSJoe Komlodi {
596eee51e8fSJoe Komlodi /*
597eee51e8fSJoe Komlodi * If the user is setting I3C_RESUME, the controller was halted.
598eee51e8fSJoe Komlodi * Try and resume execution and leave the bit cleared.
599eee51e8fSJoe Komlodi */
600eee51e8fSJoe Komlodi if (FIELD_EX32(val, DEVICE_CTRL, I3C_RESUME)) {
601eee51e8fSJoe Komlodi aspeed_i3c_device_cmd_queue_execute(s);
602eee51e8fSJoe Komlodi val = FIELD_DP32(val, DEVICE_CTRL, I3C_RESUME, 0);
603eee51e8fSJoe Komlodi }
604eee51e8fSJoe Komlodi /*
605eee51e8fSJoe Komlodi * I3C_ABORT being set sends an I3C STOP. It's cleared when the STOP is
606eee51e8fSJoe Komlodi * sent.
607eee51e8fSJoe Komlodi */
608eee51e8fSJoe Komlodi if (FIELD_EX32(val, DEVICE_CTRL, I3C_ABORT)) {
609eee51e8fSJoe Komlodi aspeed_i3c_device_end_transfer(s, /*is_i2c=*/true);
610eee51e8fSJoe Komlodi aspeed_i3c_device_end_transfer(s, /*is_i2c=*/false);
611eee51e8fSJoe Komlodi val = FIELD_DP32(val, DEVICE_CTRL, I3C_ABORT, 0);
612eee51e8fSJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TRANSFER_ABORT, 1);
613eee51e8fSJoe Komlodi aspeed_i3c_device_update_irq(s);
614eee51e8fSJoe Komlodi }
615eee51e8fSJoe Komlodi /* Update present state. */
616eee51e8fSJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS,
617eee51e8fSJoe Komlodi ASPEED_I3C_TRANSFER_STATE_IDLE);
618eee51e8fSJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS,
619eee51e8fSJoe Komlodi ASPEED_I3C_TRANSFER_STATUS_IDLE);
620eee51e8fSJoe Komlodi
621eee51e8fSJoe Komlodi s->regs[R_DEVICE_CTRL] = val;
622eee51e8fSJoe Komlodi }
623eee51e8fSJoe Komlodi
aspeed_i3c_device_target_is_i2c(AspeedI3CDevice * s,uint16_t offset)6244ba25376SJoe Komlodi static inline bool aspeed_i3c_device_target_is_i2c(AspeedI3CDevice *s,
6254ba25376SJoe Komlodi uint16_t offset)
6264ba25376SJoe Komlodi {
6274ba25376SJoe Komlodi uint16_t dev_index = R_DEVICE_ADDR_TABLE_LOC1 + offset;
6284ba25376SJoe Komlodi return FIELD_EX32(s->regs[dev_index], DEVICE_ADDR_TABLE_LOC1,
6294ba25376SJoe Komlodi LEGACY_I2C_DEVICE);
6304ba25376SJoe Komlodi }
6314ba25376SJoe Komlodi
aspeed_i3c_device_target_addr(AspeedI3CDevice * s,uint16_t offset)6324ba25376SJoe Komlodi static uint8_t aspeed_i3c_device_target_addr(AspeedI3CDevice *s,
6334ba25376SJoe Komlodi uint16_t offset)
6344ba25376SJoe Komlodi {
6354ba25376SJoe Komlodi if (offset > ASPEED_I3C_NR_DEVICES) {
6364ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Device addr table offset %d out of "
6374ba25376SJoe Komlodi "bounds\n", object_get_canonical_path(OBJECT(s)), offset);
6384ba25376SJoe Komlodi /* If we're out of bounds, return an address of 0. */
6394ba25376SJoe Komlodi return 0;
6404ba25376SJoe Komlodi }
6414ba25376SJoe Komlodi
6424ba25376SJoe Komlodi uint16_t dev_index = R_DEVICE_ADDR_TABLE_LOC1 + offset;
6434ba25376SJoe Komlodi /* I2C devices use a static address. */
6444ba25376SJoe Komlodi if (aspeed_i3c_device_target_is_i2c(s, offset)) {
6454ba25376SJoe Komlodi return FIELD_EX32(s->regs[dev_index], DEVICE_ADDR_TABLE_LOC1,
6464ba25376SJoe Komlodi DEV_STATIC_ADDR);
6474ba25376SJoe Komlodi }
6484ba25376SJoe Komlodi return FIELD_EX32(s->regs[dev_index], DEVICE_ADDR_TABLE_LOC1,
6494ba25376SJoe Komlodi DEV_DYNAMIC_ADDR);
6504ba25376SJoe Komlodi }
6514ba25376SJoe Komlodi
aspeed_i3c_device_addr_table_index_from_addr(AspeedI3CDevice * s,uint8_t addr)65293ec6949SJoe Komlodi static int aspeed_i3c_device_addr_table_index_from_addr(AspeedI3CDevice *s,
65393ec6949SJoe Komlodi uint8_t addr)
65493ec6949SJoe Komlodi {
65593ec6949SJoe Komlodi uint8_t table_size = ARRAY_FIELD_EX32(s->regs, DEVICE_ADDR_TABLE_POINTER,
65693ec6949SJoe Komlodi DEPTH);
65793ec6949SJoe Komlodi for (uint8_t i = 0; i < table_size; i++) {
65893ec6949SJoe Komlodi if (aspeed_i3c_device_target_addr(s, i) == addr) {
65993ec6949SJoe Komlodi return i;
66093ec6949SJoe Komlodi }
66193ec6949SJoe Komlodi }
66293ec6949SJoe Komlodi return -1;
66393ec6949SJoe Komlodi }
66493ec6949SJoe Komlodi
aspeed_i3c_device_send_disec(AspeedI3CDevice * s)66593ec6949SJoe Komlodi static void aspeed_i3c_device_send_disec(AspeedI3CDevice *s)
66693ec6949SJoe Komlodi {
66793ec6949SJoe Komlodi uint8_t ccc = I3C_CCC_DISEC;
66893ec6949SJoe Komlodi if (s->ibi_data.send_direct_disec) {
66993ec6949SJoe Komlodi ccc = I3C_CCCD_DISEC;
67093ec6949SJoe Komlodi }
67193ec6949SJoe Komlodi
67293ec6949SJoe Komlodi aspeed_i3c_device_send_start(s, I3C_BROADCAST, /*is_recv=*/false,
67393ec6949SJoe Komlodi /*is_i2c=*/false);
67493ec6949SJoe Komlodi aspeed_i3c_device_send_byte(s, ccc, /*is_i2c=*/false);
67593ec6949SJoe Komlodi if (s->ibi_data.send_direct_disec) {
67693ec6949SJoe Komlodi aspeed_i3c_device_send_start(s, s->ibi_data.disec_addr,
67793ec6949SJoe Komlodi /*is_recv=*/false, /*is_i2c=*/false);
67893ec6949SJoe Komlodi }
67993ec6949SJoe Komlodi aspeed_i3c_device_send_byte(s, s->ibi_data.disec_byte, /*is_i2c=*/false);
68093ec6949SJoe Komlodi }
68193ec6949SJoe Komlodi
aspeed_i3c_device_handle_hj(AspeedI3CDevice * s)68293ec6949SJoe Komlodi static int aspeed_i3c_device_handle_hj(AspeedI3CDevice *s)
68393ec6949SJoe Komlodi {
68493ec6949SJoe Komlodi if (ARRAY_FIELD_EX32(s->regs, IBI_QUEUE_CTRL, NOTIFY_REJECTED_HOT_JOIN)) {
68593ec6949SJoe Komlodi s->ibi_data.notify_ibi_nack = true;
68693ec6949SJoe Komlodi }
68793ec6949SJoe Komlodi
68893ec6949SJoe Komlodi bool nack_and_disable = ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL,
68993ec6949SJoe Komlodi HOT_JOIN_ACK_NACK_CTRL);
69093ec6949SJoe Komlodi if (nack_and_disable) {
69193ec6949SJoe Komlodi s->ibi_data.ibi_queue_status = FIELD_DP32(s->ibi_data.ibi_queue_status,
69293ec6949SJoe Komlodi IBI_QUEUE_STATUS,
69393ec6949SJoe Komlodi IBI_STATUS, 1);
69493ec6949SJoe Komlodi s->ibi_data.ibi_nacked = true;
69593ec6949SJoe Komlodi s->ibi_data.disec_byte = DISEC_HJ;
69693ec6949SJoe Komlodi return -1;
69793ec6949SJoe Komlodi }
69893ec6949SJoe Komlodi return 0;
69993ec6949SJoe Komlodi }
70093ec6949SJoe Komlodi
aspeed_i3c_device_handle_ctlr_req(AspeedI3CDevice * s,uint8_t addr)70193ec6949SJoe Komlodi static int aspeed_i3c_device_handle_ctlr_req(AspeedI3CDevice *s, uint8_t addr)
70293ec6949SJoe Komlodi {
70393ec6949SJoe Komlodi if (ARRAY_FIELD_EX32(s->regs, IBI_QUEUE_CTRL, NOTIFY_REJECTED_MASTER_REQ)) {
70493ec6949SJoe Komlodi s->ibi_data.notify_ibi_nack = true;
70593ec6949SJoe Komlodi }
70693ec6949SJoe Komlodi
70793ec6949SJoe Komlodi int table_offset = aspeed_i3c_device_addr_table_index_from_addr(s, addr);
70893ec6949SJoe Komlodi /* Doesn't exist in the table, NACK it, don't DISEC. */
70993ec6949SJoe Komlodi if (table_offset < 0) {
71093ec6949SJoe Komlodi return -1;
71193ec6949SJoe Komlodi }
71293ec6949SJoe Komlodi
71393ec6949SJoe Komlodi table_offset += R_DEVICE_ADDR_TABLE_LOC1;
71493ec6949SJoe Komlodi if (FIELD_EX32(s->regs[table_offset], DEVICE_ADDR_TABLE_LOC1, MR_REJECT)) {
71593ec6949SJoe Komlodi s->ibi_data.ibi_queue_status = FIELD_DP32(s->ibi_data.ibi_queue_status,
71693ec6949SJoe Komlodi IBI_QUEUE_STATUS,
71793ec6949SJoe Komlodi IBI_STATUS, 1);
71893ec6949SJoe Komlodi s->ibi_data.ibi_nacked = true;
71993ec6949SJoe Komlodi s->ibi_data.disec_addr = addr;
72093ec6949SJoe Komlodi /* Tell the requester to disable controller role requests. */
72193ec6949SJoe Komlodi s->ibi_data.disec_byte = DISEC_CR;
72293ec6949SJoe Komlodi s->ibi_data.send_direct_disec = true;
72393ec6949SJoe Komlodi return -1;
72493ec6949SJoe Komlodi }
72593ec6949SJoe Komlodi return 0;
72693ec6949SJoe Komlodi }
72793ec6949SJoe Komlodi
aspeed_i3c_device_handle_targ_irq(AspeedI3CDevice * s,uint8_t addr)72893ec6949SJoe Komlodi static int aspeed_i3c_device_handle_targ_irq(AspeedI3CDevice *s, uint8_t addr)
72993ec6949SJoe Komlodi {
73093ec6949SJoe Komlodi if (ARRAY_FIELD_EX32(s->regs, IBI_QUEUE_CTRL, NOTIFY_REJECTED_SLAVE_IRQ)) {
73193ec6949SJoe Komlodi s->ibi_data.notify_ibi_nack = true;
73293ec6949SJoe Komlodi }
73393ec6949SJoe Komlodi
73493ec6949SJoe Komlodi int table_offset = aspeed_i3c_device_addr_table_index_from_addr(s, addr);
73593ec6949SJoe Komlodi /* Doesn't exist in the table, NACK it, don't DISEC. */
73693ec6949SJoe Komlodi if (table_offset < 0) {
73793ec6949SJoe Komlodi return -1;
73893ec6949SJoe Komlodi }
73993ec6949SJoe Komlodi
74093ec6949SJoe Komlodi table_offset += R_DEVICE_ADDR_TABLE_LOC1;
74193ec6949SJoe Komlodi if (FIELD_EX32(s->regs[table_offset], DEVICE_ADDR_TABLE_LOC1, SIR_REJECT)) {
74293ec6949SJoe Komlodi s->ibi_data.ibi_queue_status = FIELD_DP32(s->ibi_data.ibi_queue_status,
74393ec6949SJoe Komlodi IBI_QUEUE_STATUS,
74493ec6949SJoe Komlodi IBI_STATUS, 1);
74593ec6949SJoe Komlodi s->ibi_data.ibi_nacked = true;
74693ec6949SJoe Komlodi s->ibi_data.disec_addr = addr;
74793ec6949SJoe Komlodi /* Tell the requester to disable interrupts. */
74893ec6949SJoe Komlodi s->ibi_data.disec_byte = DISEC_INT;
74993ec6949SJoe Komlodi s->ibi_data.send_direct_disec = true;
75093ec6949SJoe Komlodi return -1;
75193ec6949SJoe Komlodi }
75293ec6949SJoe Komlodi return 0;
75393ec6949SJoe Komlodi }
75493ec6949SJoe Komlodi
aspeed_i3c_device_ibi_handle(I3CBus * bus,I3CTarget * target,uint8_t addr,bool is_recv)75593ec6949SJoe Komlodi static int aspeed_i3c_device_ibi_handle(I3CBus *bus, I3CTarget *target,
75693ec6949SJoe Komlodi uint8_t addr, bool is_recv)
75793ec6949SJoe Komlodi {
75893ec6949SJoe Komlodi AspeedI3CDevice *s = ASPEED_I3C_DEVICE(bus->qbus.parent);
75993ec6949SJoe Komlodi
76093ec6949SJoe Komlodi trace_aspeed_i3c_device_ibi_handle(s->id, addr, is_recv);
76193ec6949SJoe Komlodi s->ibi_data.ibi_queue_status = FIELD_DP32(s->ibi_data.ibi_queue_status,
76293ec6949SJoe Komlodi IBI_QUEUE_STATUS, IBI_ID,
76393ec6949SJoe Komlodi (addr << 1) | is_recv);
76493ec6949SJoe Komlodi /* Is this a hot join request? */
76593ec6949SJoe Komlodi if (addr == I3C_HJ_ADDR) {
76693ec6949SJoe Komlodi return aspeed_i3c_device_handle_hj(s);
76793ec6949SJoe Komlodi }
76893ec6949SJoe Komlodi /* Is secondary controller requesting access? */
76993ec6949SJoe Komlodi if (addr == target->address && !is_recv) {
77093ec6949SJoe Komlodi return aspeed_i3c_device_handle_ctlr_req(s, addr);
77193ec6949SJoe Komlodi }
77293ec6949SJoe Komlodi /* Is this a target IRQ? */
77393ec6949SJoe Komlodi if (addr == target->address && is_recv) {
77493ec6949SJoe Komlodi return aspeed_i3c_device_handle_targ_irq(s, addr);
77593ec6949SJoe Komlodi }
77693ec6949SJoe Komlodi
77793ec6949SJoe Komlodi /* Not sure what this is, NACK it. */
77893ec6949SJoe Komlodi return -1;
77993ec6949SJoe Komlodi }
78093ec6949SJoe Komlodi
aspeed_i3c_device_ibi_recv(I3CBus * bus,uint8_t data)78193ec6949SJoe Komlodi static int aspeed_i3c_device_ibi_recv(I3CBus *bus, uint8_t data)
78293ec6949SJoe Komlodi {
78393ec6949SJoe Komlodi AspeedI3CDevice *s = ASPEED_I3C_DEVICE(bus->qbus.parent);
78493ec6949SJoe Komlodi if (fifo8_is_full(&s->ibi_data.ibi_intermediate_queue)) {
78593ec6949SJoe Komlodi return -1;
78693ec6949SJoe Komlodi }
78793ec6949SJoe Komlodi
78893ec6949SJoe Komlodi fifo8_push(&s->ibi_data.ibi_intermediate_queue, data);
78993ec6949SJoe Komlodi trace_aspeed_i3c_device_ibi_recv(s->id, data);
79093ec6949SJoe Komlodi return 0;
79193ec6949SJoe Komlodi }
79293ec6949SJoe Komlodi
aspeed_i3c_device_ibi_queue_push(AspeedI3CDevice * s)79393ec6949SJoe Komlodi static void aspeed_i3c_device_ibi_queue_push(AspeedI3CDevice *s)
79493ec6949SJoe Komlodi {
79593ec6949SJoe Komlodi /* Stored value is in 32-bit chunks, convert it to byte chunks. */
79693ec6949SJoe Komlodi uint8_t ibi_slice_size = aspeed_i3c_device_ibi_slice_size(s);
79793ec6949SJoe Komlodi uint8_t num_slices = fifo8_num_used(&s->ibi_data.ibi_intermediate_queue) /
79893ec6949SJoe Komlodi ibi_slice_size;
79993ec6949SJoe Komlodi uint8_t ibi_status_count = num_slices;
80093ec6949SJoe Komlodi union {
80193ec6949SJoe Komlodi uint8_t b[sizeof(uint32_t)];
80293ec6949SJoe Komlodi uint32_t val32;
80393ec6949SJoe Komlodi } ibi_data = {
80493ec6949SJoe Komlodi .val32 = 0
80593ec6949SJoe Komlodi };
80693ec6949SJoe Komlodi
80793ec6949SJoe Komlodi /* The report was suppressed, do nothing. */
80893ec6949SJoe Komlodi if (s->ibi_data.ibi_nacked && !s->ibi_data.notify_ibi_nack) {
80993ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS,
81093ec6949SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_IDLE);
81193ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS,
81293ec6949SJoe Komlodi ASPEED_I3C_TRANSFER_STATUS_IDLE);
81393ec6949SJoe Komlodi return;
81493ec6949SJoe Komlodi }
81593ec6949SJoe Komlodi
81693ec6949SJoe Komlodi /* If we don't have any slices to push, just push the status. */
81793ec6949SJoe Komlodi if (num_slices == 0) {
81893ec6949SJoe Komlodi s->ibi_data.ibi_queue_status =
81993ec6949SJoe Komlodi FIELD_DP32(s->ibi_data.ibi_queue_status, IBI_QUEUE_STATUS,
82093ec6949SJoe Komlodi LAST_STATUS, 1);
82193ec6949SJoe Komlodi fifo32_push(&s->ibi_queue, s->ibi_data.ibi_queue_status);
82293ec6949SJoe Komlodi ibi_status_count = 1;
82393ec6949SJoe Komlodi }
82493ec6949SJoe Komlodi
82593ec6949SJoe Komlodi for (uint8_t i = 0; i < num_slices; i++) {
82693ec6949SJoe Komlodi /* If this is the last slice, set LAST_STATUS. */
82793ec6949SJoe Komlodi if (fifo8_num_used(&s->ibi_data.ibi_intermediate_queue) <
82893ec6949SJoe Komlodi ibi_slice_size) {
82993ec6949SJoe Komlodi s->ibi_data.ibi_queue_status =
83093ec6949SJoe Komlodi FIELD_DP32(s->ibi_data.ibi_queue_status, IBI_QUEUE_STATUS,
83193ec6949SJoe Komlodi IBI_DATA_LEN,
83293ec6949SJoe Komlodi fifo8_num_used(&s->ibi_data.ibi_intermediate_queue));
83393ec6949SJoe Komlodi s->ibi_data.ibi_queue_status =
83493ec6949SJoe Komlodi FIELD_DP32(s->ibi_data.ibi_queue_status, IBI_QUEUE_STATUS,
83593ec6949SJoe Komlodi LAST_STATUS, 1);
83693ec6949SJoe Komlodi } else {
83793ec6949SJoe Komlodi s->ibi_data.ibi_queue_status =
83893ec6949SJoe Komlodi FIELD_DP32(s->ibi_data.ibi_queue_status, IBI_QUEUE_STATUS,
83993ec6949SJoe Komlodi IBI_DATA_LEN, ibi_slice_size);
84093ec6949SJoe Komlodi }
84193ec6949SJoe Komlodi
84293ec6949SJoe Komlodi /* Push the IBI status header. */
84393ec6949SJoe Komlodi fifo32_push(&s->ibi_queue, s->ibi_data.ibi_queue_status);
84493ec6949SJoe Komlodi /* Move each IBI byte into a 32-bit word and push it into the queue. */
84593ec6949SJoe Komlodi for (uint8_t j = 0; j < ibi_slice_size; ++j) {
84693ec6949SJoe Komlodi if (fifo8_is_empty(&s->ibi_data.ibi_intermediate_queue)) {
84793ec6949SJoe Komlodi break;
84893ec6949SJoe Komlodi }
84993ec6949SJoe Komlodi
85093ec6949SJoe Komlodi ibi_data.b[j & 3] = fifo8_pop(&s->ibi_data.ibi_intermediate_queue);
85193ec6949SJoe Komlodi /* We have 32-bits, push it to the IBI FIFO. */
85293ec6949SJoe Komlodi if ((j & 0x03) == 0x03) {
85393ec6949SJoe Komlodi fifo32_push(&s->ibi_queue, ibi_data.val32);
85493ec6949SJoe Komlodi ibi_data.val32 = 0;
85593ec6949SJoe Komlodi }
85693ec6949SJoe Komlodi }
85793ec6949SJoe Komlodi /* If the data isn't 32-bit aligned, push the leftover bytes. */
85893ec6949SJoe Komlodi if (ibi_slice_size & 0x03) {
85993ec6949SJoe Komlodi fifo32_push(&s->ibi_queue, ibi_data.val32);
86093ec6949SJoe Komlodi }
86193ec6949SJoe Komlodi
86293ec6949SJoe Komlodi /* Clear out the data length for the next iteration. */
86393ec6949SJoe Komlodi s->ibi_data.ibi_queue_status = FIELD_DP32(s->ibi_data.ibi_queue_status,
86493ec6949SJoe Komlodi IBI_QUEUE_STATUS, IBI_DATA_LEN, 0);
86593ec6949SJoe Komlodi }
86693ec6949SJoe Komlodi
86793ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, IBI_BUF_BLR,
86893ec6949SJoe Komlodi fifo32_num_used(&s->ibi_queue));
86993ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, IBI_STATUS_CNT,
87093ec6949SJoe Komlodi ibi_status_count);
87193ec6949SJoe Komlodi /* Threshold is the register value + 1. */
87293ec6949SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL,
87393ec6949SJoe Komlodi IBI_STATUS_THLD) + 1;
87493ec6949SJoe Komlodi if (fifo32_num_used(&s->ibi_queue) >= threshold) {
87593ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, IBI_THLD, 1);
87693ec6949SJoe Komlodi aspeed_i3c_device_update_irq(s);
87793ec6949SJoe Komlodi }
87893ec6949SJoe Komlodi
87993ec6949SJoe Komlodi /* State update. */
88093ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS,
88193ec6949SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_IDLE);
88293ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS,
88393ec6949SJoe Komlodi ASPEED_I3C_TRANSFER_STATUS_IDLE);
88493ec6949SJoe Komlodi }
88593ec6949SJoe Komlodi
aspeed_i3c_device_ibi_finish(I3CBus * bus)88693ec6949SJoe Komlodi static int aspeed_i3c_device_ibi_finish(I3CBus *bus)
88793ec6949SJoe Komlodi {
88893ec6949SJoe Komlodi AspeedI3CDevice *s = ASPEED_I3C_DEVICE(bus->qbus.parent);
88993ec6949SJoe Komlodi bool nack_and_disable_hj = ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL,
89093ec6949SJoe Komlodi HOT_JOIN_ACK_NACK_CTRL);
89193ec6949SJoe Komlodi if (nack_and_disable_hj || s->ibi_data.send_direct_disec) {
89293ec6949SJoe Komlodi aspeed_i3c_device_send_disec(s);
89393ec6949SJoe Komlodi }
89493ec6949SJoe Komlodi aspeed_i3c_device_ibi_queue_push(s);
89593ec6949SJoe Komlodi
89693ec6949SJoe Komlodi /* Clear out the intermediate values. */
89793ec6949SJoe Komlodi s->ibi_data.ibi_queue_status = 0;
89893ec6949SJoe Komlodi s->ibi_data.disec_addr = 0;
89993ec6949SJoe Komlodi s->ibi_data.disec_byte = 0;
90093ec6949SJoe Komlodi s->ibi_data.send_direct_disec = false;
90193ec6949SJoe Komlodi s->ibi_data.notify_ibi_nack = false;
90293ec6949SJoe Komlodi s->ibi_data.ibi_nacked = false;
90393ec6949SJoe Komlodi
90493ec6949SJoe Komlodi return 0;
90593ec6949SJoe Komlodi }
90693ec6949SJoe Komlodi
aspeed_i3c_device_intr_status_r(AspeedI3CDevice * s)9073816bedaSJoe Komlodi static uint32_t aspeed_i3c_device_intr_status_r(AspeedI3CDevice *s)
9083816bedaSJoe Komlodi {
9093816bedaSJoe Komlodi /* Only return the status whose corresponding EN bits are set. */
9103816bedaSJoe Komlodi return s->regs[R_INTR_STATUS] & s->regs[R_INTR_STATUS_EN];
9113816bedaSJoe Komlodi }
9123816bedaSJoe Komlodi
aspeed_i3c_device_intr_status_w(AspeedI3CDevice * s,uint32_t val)9133816bedaSJoe Komlodi static void aspeed_i3c_device_intr_status_w(AspeedI3CDevice *s, uint32_t val)
9143816bedaSJoe Komlodi {
9153816bedaSJoe Komlodi /* INTR_STATUS[13:5] is w1c, other bits are RO. */
9163816bedaSJoe Komlodi val &= 0x3fe0;
9173816bedaSJoe Komlodi s->regs[R_INTR_STATUS] &= ~val;
9183816bedaSJoe Komlodi
9193816bedaSJoe Komlodi aspeed_i3c_device_update_irq(s);
9203816bedaSJoe Komlodi }
9213816bedaSJoe Komlodi
aspeed_i3c_device_intr_status_en_w(AspeedI3CDevice * s,uint32_t val)9223816bedaSJoe Komlodi static void aspeed_i3c_device_intr_status_en_w(AspeedI3CDevice *s, uint32_t val)
9233816bedaSJoe Komlodi {
9243816bedaSJoe Komlodi s->regs[R_INTR_STATUS_EN] = val;
9253816bedaSJoe Komlodi aspeed_i3c_device_update_irq(s);
9263816bedaSJoe Komlodi }
9273816bedaSJoe Komlodi
aspeed_i3c_device_intr_signal_en_w(AspeedI3CDevice * s,uint32_t val)9283816bedaSJoe Komlodi static void aspeed_i3c_device_intr_signal_en_w(AspeedI3CDevice *s, uint32_t val)
9293816bedaSJoe Komlodi {
9303816bedaSJoe Komlodi s->regs[R_INTR_SIGNAL_EN] = val;
9313816bedaSJoe Komlodi aspeed_i3c_device_update_irq(s);
9323816bedaSJoe Komlodi }
9333816bedaSJoe Komlodi
aspeed_i3c_device_intr_force_w(AspeedI3CDevice * s,uint32_t val)9343816bedaSJoe Komlodi static void aspeed_i3c_device_intr_force_w(AspeedI3CDevice *s, uint32_t val)
9353816bedaSJoe Komlodi {
9363816bedaSJoe Komlodi /* INTR_FORCE is WO, just set the corresponding INTR_STATUS bits. */
9373816bedaSJoe Komlodi s->regs[R_INTR_STATUS] = val;
9383816bedaSJoe Komlodi aspeed_i3c_device_update_irq(s);
9393816bedaSJoe Komlodi }
9403816bedaSJoe Komlodi
aspeed_i3c_device_cmd_queue_reset(AspeedI3CDevice * s)941*66ae8f22SJoe Komlodi static void aspeed_i3c_device_cmd_queue_reset(AspeedI3CDevice *s)
942*66ae8f22SJoe Komlodi {
943*66ae8f22SJoe Komlodi fifo32_reset(&s->cmd_queue);
944*66ae8f22SJoe Komlodi
945*66ae8f22SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, CMD_QUEUE_EMPTY_LOC,
946*66ae8f22SJoe Komlodi fifo32_num_free(&s->cmd_queue));
947*66ae8f22SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL,
948*66ae8f22SJoe Komlodi CMD_BUF_EMPTY_THLD);
949*66ae8f22SJoe Komlodi if (fifo32_num_free(&s->cmd_queue) >= empty_threshold) {
950*66ae8f22SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, CMD_QUEUE_RDY, 1);
951*66ae8f22SJoe Komlodi aspeed_i3c_device_update_irq(s);
952*66ae8f22SJoe Komlodi };
953*66ae8f22SJoe Komlodi }
954*66ae8f22SJoe Komlodi
aspeed_i3c_device_resp_queue_reset(AspeedI3CDevice * s)955*66ae8f22SJoe Komlodi static void aspeed_i3c_device_resp_queue_reset(AspeedI3CDevice *s)
956*66ae8f22SJoe Komlodi {
957*66ae8f22SJoe Komlodi fifo32_reset(&s->resp_queue);
958*66ae8f22SJoe Komlodi
959*66ae8f22SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, RESP_BUF_BLR,
960*66ae8f22SJoe Komlodi fifo32_num_used(&s->resp_queue));
961*66ae8f22SJoe Komlodi /*
962*66ae8f22SJoe Komlodi * This interrupt will always be cleared because the threshold is a minimum
963*66ae8f22SJoe Komlodi * of 1 and the queue size is 0.
964*66ae8f22SJoe Komlodi */
965*66ae8f22SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RESP_RDY, 0);
966*66ae8f22SJoe Komlodi aspeed_i3c_device_update_irq(s);
967*66ae8f22SJoe Komlodi }
968*66ae8f22SJoe Komlodi
aspeed_i3c_device_ibi_queue_reset(AspeedI3CDevice * s)969*66ae8f22SJoe Komlodi static void aspeed_i3c_device_ibi_queue_reset(AspeedI3CDevice *s)
970*66ae8f22SJoe Komlodi {
971*66ae8f22SJoe Komlodi fifo32_reset(&s->ibi_queue);
972*66ae8f22SJoe Komlodi
973*66ae8f22SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, IBI_BUF_BLR,
974*66ae8f22SJoe Komlodi fifo32_num_used(&s->resp_queue));
975*66ae8f22SJoe Komlodi /*
976*66ae8f22SJoe Komlodi * This interrupt will always be cleared because the threshold is a minimum
977*66ae8f22SJoe Komlodi * of 1 and the queue size is 0.
978*66ae8f22SJoe Komlodi */
979*66ae8f22SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, IBI_THLD, 0);
980*66ae8f22SJoe Komlodi aspeed_i3c_device_update_irq(s);
981*66ae8f22SJoe Komlodi }
982*66ae8f22SJoe Komlodi
aspeed_i3c_device_tx_queue_reset(AspeedI3CDevice * s)983*66ae8f22SJoe Komlodi static void aspeed_i3c_device_tx_queue_reset(AspeedI3CDevice *s)
984*66ae8f22SJoe Komlodi {
985*66ae8f22SJoe Komlodi fifo32_reset(&s->tx_queue);
986*66ae8f22SJoe Komlodi
987*66ae8f22SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, TX_BUF_EMPTY_LOC,
988*66ae8f22SJoe Komlodi fifo32_num_free(&s->tx_queue));
989*66ae8f22SJoe Komlodi /* TX buf is empty, so this interrupt will always be set. */
990*66ae8f22SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TX_THLD, 1);
991*66ae8f22SJoe Komlodi aspeed_i3c_device_update_irq(s);
992*66ae8f22SJoe Komlodi }
993*66ae8f22SJoe Komlodi
aspeed_i3c_device_rx_queue_reset(AspeedI3CDevice * s)994*66ae8f22SJoe Komlodi static void aspeed_i3c_device_rx_queue_reset(AspeedI3CDevice *s)
995*66ae8f22SJoe Komlodi {
996*66ae8f22SJoe Komlodi fifo32_reset(&s->rx_queue);
997*66ae8f22SJoe Komlodi
998*66ae8f22SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, RX_BUF_BLR,
999*66ae8f22SJoe Komlodi fifo32_num_used(&s->resp_queue));
1000*66ae8f22SJoe Komlodi /*
1001*66ae8f22SJoe Komlodi * This interrupt will always be cleared because the threshold is a minimum
1002*66ae8f22SJoe Komlodi * of 1 and the queue size is 0.
1003*66ae8f22SJoe Komlodi */
1004*66ae8f22SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RX_THLD, 0);
1005*66ae8f22SJoe Komlodi aspeed_i3c_device_update_irq(s);
1006*66ae8f22SJoe Komlodi }
1007*66ae8f22SJoe Komlodi
aspeed_i3c_device_reset(DeviceState * dev)1008*66ae8f22SJoe Komlodi static void aspeed_i3c_device_reset(DeviceState *dev)
1009*66ae8f22SJoe Komlodi {
1010*66ae8f22SJoe Komlodi AspeedI3CDevice *s = ASPEED_I3C_DEVICE(dev);
1011*66ae8f22SJoe Komlodi trace_aspeed_i3c_device_reset(s->id);
1012*66ae8f22SJoe Komlodi
1013*66ae8f22SJoe Komlodi memcpy(s->regs, ast2600_i3c_device_resets, sizeof(s->regs));
1014*66ae8f22SJoe Komlodi aspeed_i3c_device_cmd_queue_reset(s);
1015*66ae8f22SJoe Komlodi aspeed_i3c_device_resp_queue_reset(s);
1016*66ae8f22SJoe Komlodi aspeed_i3c_device_ibi_queue_reset(s);
1017*66ae8f22SJoe Komlodi aspeed_i3c_device_tx_queue_reset(s);
1018*66ae8f22SJoe Komlodi aspeed_i3c_device_rx_queue_reset(s);
1019*66ae8f22SJoe Komlodi }
1020*66ae8f22SJoe Komlodi
aspeed_i3c_device_reset_ctrl_w(AspeedI3CDevice * s,uint32_t val)1021*66ae8f22SJoe Komlodi static void aspeed_i3c_device_reset_ctrl_w(AspeedI3CDevice *s, uint32_t val)
1022*66ae8f22SJoe Komlodi {
1023*66ae8f22SJoe Komlodi if (FIELD_EX32(val, RESET_CTRL, CORE_RESET)) {
1024*66ae8f22SJoe Komlodi aspeed_i3c_device_reset(DEVICE(s));
1025*66ae8f22SJoe Komlodi }
1026*66ae8f22SJoe Komlodi if (FIELD_EX32(val, RESET_CTRL, CMD_QUEUE_RESET)) {
1027*66ae8f22SJoe Komlodi aspeed_i3c_device_cmd_queue_reset(s);
1028*66ae8f22SJoe Komlodi }
1029*66ae8f22SJoe Komlodi if (FIELD_EX32(val, RESET_CTRL, RESP_QUEUE_RESET)) {
1030*66ae8f22SJoe Komlodi aspeed_i3c_device_resp_queue_reset(s);
1031*66ae8f22SJoe Komlodi }
1032*66ae8f22SJoe Komlodi if (FIELD_EX32(val, RESET_CTRL, TX_BUF_RESET)) {
1033*66ae8f22SJoe Komlodi aspeed_i3c_device_tx_queue_reset(s);
1034*66ae8f22SJoe Komlodi }
1035*66ae8f22SJoe Komlodi if (FIELD_EX32(val, RESET_CTRL, RX_BUF_RESET)) {
1036*66ae8f22SJoe Komlodi aspeed_i3c_device_rx_queue_reset(s);
1037*66ae8f22SJoe Komlodi }
1038*66ae8f22SJoe Komlodi if (FIELD_EX32(val, RESET_CTRL, IBI_QUEUE_RESET)) {
1039*66ae8f22SJoe Komlodi aspeed_i3c_device_ibi_queue_reset(s);
1040*66ae8f22SJoe Komlodi }
1041*66ae8f22SJoe Komlodi }
1042*66ae8f22SJoe Komlodi
aspeed_i3c_device_pop_rx(AspeedI3CDevice * s)10434ba25376SJoe Komlodi static uint32_t aspeed_i3c_device_pop_rx(AspeedI3CDevice *s)
10444ba25376SJoe Komlodi {
10454ba25376SJoe Komlodi if (fifo32_is_empty(&s->rx_queue)) {
10464ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to read RX FIFO when empty\n",
10474ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s)));
10484ba25376SJoe Komlodi return 0;
10494ba25376SJoe Komlodi }
10504ba25376SJoe Komlodi
10514ba25376SJoe Komlodi uint32_t val = fifo32_pop(&s->rx_queue);
10524ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, RX_BUF_BLR,
10534ba25376SJoe Komlodi fifo32_num_used(&s->rx_queue));
10544ba25376SJoe Komlodi
10554ba25376SJoe Komlodi /* Threshold is 2^RX_BUF_THLD. */
10564ba25376SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, DATA_BUFFER_THLD_CTRL,
10574ba25376SJoe Komlodi RX_BUF_THLD);
10584ba25376SJoe Komlodi threshold = aspeed_i3c_device_fifo_threshold_from_reg(threshold);
10594ba25376SJoe Komlodi if (fifo32_num_used(&s->rx_queue) < threshold) {
10604ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RX_THLD, 0);
10614ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s);
10624ba25376SJoe Komlodi }
10634ba25376SJoe Komlodi
10644ba25376SJoe Komlodi trace_aspeed_i3c_device_pop_rx(s->id, val);
10654ba25376SJoe Komlodi return val;
10664ba25376SJoe Komlodi }
10674ba25376SJoe Komlodi
aspeed_i3c_device_ibi_queue_r(AspeedI3CDevice * s)106893ec6949SJoe Komlodi static uint32_t aspeed_i3c_device_ibi_queue_r(AspeedI3CDevice *s)
106993ec6949SJoe Komlodi {
107093ec6949SJoe Komlodi if (fifo32_is_empty(&s->ibi_queue)) {
107193ec6949SJoe Komlodi return 0;
107293ec6949SJoe Komlodi }
107393ec6949SJoe Komlodi
107493ec6949SJoe Komlodi uint32_t val = fifo32_pop(&s->ibi_queue);
107593ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, IBI_BUF_BLR,
107693ec6949SJoe Komlodi fifo32_num_used(&s->ibi_queue));
107793ec6949SJoe Komlodi /* Threshold is the register value + 1. */
107893ec6949SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL,
107993ec6949SJoe Komlodi IBI_STATUS_THLD) + 1;
108093ec6949SJoe Komlodi if (fifo32_num_used(&s->ibi_queue) < threshold) {
108193ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, IBI_THLD, 0);
108293ec6949SJoe Komlodi aspeed_i3c_device_update_irq(s);
108393ec6949SJoe Komlodi }
108493ec6949SJoe Komlodi return val;
108593ec6949SJoe Komlodi }
108693ec6949SJoe Komlodi
aspeed_i3c_device_resp_queue_port_r(AspeedI3CDevice * s)10874ba25376SJoe Komlodi static uint32_t aspeed_i3c_device_resp_queue_port_r(AspeedI3CDevice *s)
10884ba25376SJoe Komlodi {
10894ba25376SJoe Komlodi if (fifo32_is_empty(&s->resp_queue)) {
10904ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to read response FIFO when "
10914ba25376SJoe Komlodi "empty\n", object_get_canonical_path(OBJECT(s)));
10924ba25376SJoe Komlodi return 0;
10934ba25376SJoe Komlodi }
10944ba25376SJoe Komlodi
10954ba25376SJoe Komlodi uint32_t val = fifo32_pop(&s->resp_queue);
10964ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, RESP_BUF_BLR,
10974ba25376SJoe Komlodi fifo32_num_used(&s->resp_queue));
10984ba25376SJoe Komlodi
10994ba25376SJoe Komlodi /* Threshold is the register value + 1. */
11004ba25376SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL,
11014ba25376SJoe Komlodi RESP_BUF_THLD) + 1;
11024ba25376SJoe Komlodi if (fifo32_num_used(&s->resp_queue) < threshold) {
11034ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RESP_RDY, 0);
11044ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s);
11054ba25376SJoe Komlodi }
11064ba25376SJoe Komlodi
11074ba25376SJoe Komlodi return val;
11084ba25376SJoe Komlodi }
11094ba25376SJoe Komlodi
aspeed_i3c_device_read(void * opaque,hwaddr offset,unsigned size)11107d87775fSJoe Komlodi static uint64_t aspeed_i3c_device_read(void *opaque, hwaddr offset,
11117d87775fSJoe Komlodi unsigned size)
11127d87775fSJoe Komlodi {
11137d87775fSJoe Komlodi AspeedI3CDevice *s = ASPEED_I3C_DEVICE(opaque);
11147d87775fSJoe Komlodi uint32_t addr = offset >> 2;
11157d87775fSJoe Komlodi uint64_t value;
11167d87775fSJoe Komlodi
11177d87775fSJoe Komlodi switch (addr) {
111809467a8aSJoe Komlodi /* RAZ */
11197d87775fSJoe Komlodi case R_COMMAND_QUEUE_PORT:
112009467a8aSJoe Komlodi case R_RESET_CTRL:
112109467a8aSJoe Komlodi case R_INTR_FORCE:
11227d87775fSJoe Komlodi value = 0;
11237d87775fSJoe Komlodi break;
112493ec6949SJoe Komlodi case R_IBI_QUEUE_DATA:
112593ec6949SJoe Komlodi value = aspeed_i3c_device_ibi_queue_r(s);
112693ec6949SJoe Komlodi break;
11273816bedaSJoe Komlodi case R_INTR_STATUS:
11283816bedaSJoe Komlodi value = aspeed_i3c_device_intr_status_r(s);
11293816bedaSJoe Komlodi break;
11304ba25376SJoe Komlodi case R_RX_TX_DATA_PORT:
11314ba25376SJoe Komlodi value = aspeed_i3c_device_pop_rx(s);
11324ba25376SJoe Komlodi break;
11334ba25376SJoe Komlodi case R_RESPONSE_QUEUE_PORT:
11344ba25376SJoe Komlodi value = aspeed_i3c_device_resp_queue_port_r(s);
11354ba25376SJoe Komlodi break;
11367d87775fSJoe Komlodi default:
11377d87775fSJoe Komlodi value = s->regs[addr];
11387d87775fSJoe Komlodi break;
11397d87775fSJoe Komlodi }
11407d87775fSJoe Komlodi
11417d87775fSJoe Komlodi trace_aspeed_i3c_device_read(s->id, offset, value);
11427d87775fSJoe Komlodi
11437d87775fSJoe Komlodi return value;
11447d87775fSJoe Komlodi }
11457d87775fSJoe Komlodi
aspeed_i3c_device_resp_queue_push(AspeedI3CDevice * s,uint8_t err,uint8_t tid,uint8_t ccc_type,uint16_t data_len)11464ba25376SJoe Komlodi static void aspeed_i3c_device_resp_queue_push(AspeedI3CDevice *s,
11474ba25376SJoe Komlodi uint8_t err, uint8_t tid,
11484ba25376SJoe Komlodi uint8_t ccc_type,
11494ba25376SJoe Komlodi uint16_t data_len)
11504ba25376SJoe Komlodi {
11514ba25376SJoe Komlodi uint32_t val = 0;
11524ba25376SJoe Komlodi val = FIELD_DP32(val, RESPONSE_QUEUE_PORT, ERR_STATUS, err);
11534ba25376SJoe Komlodi val = FIELD_DP32(val, RESPONSE_QUEUE_PORT, TID, tid);
11544ba25376SJoe Komlodi val = FIELD_DP32(val, RESPONSE_QUEUE_PORT, CCCT, ccc_type);
11554ba25376SJoe Komlodi val = FIELD_DP32(val, RESPONSE_QUEUE_PORT, DL, data_len);
11564ba25376SJoe Komlodi if (!fifo32_is_full(&s->resp_queue)) {
11574ba25376SJoe Komlodi trace_aspeed_i3c_device_resp_queue_push(s->id, val);
11584ba25376SJoe Komlodi fifo32_push(&s->resp_queue, val);
11594ba25376SJoe Komlodi }
11604ba25376SJoe Komlodi
11614ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, RESP_BUF_BLR,
11624ba25376SJoe Komlodi fifo32_num_used(&s->resp_queue));
11634ba25376SJoe Komlodi /* Threshold is the register value + 1. */
11644ba25376SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL,
11654ba25376SJoe Komlodi RESP_BUF_THLD) + 1;
11664ba25376SJoe Komlodi if (fifo32_num_used(&s->resp_queue) >= threshold) {
11674ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RESP_RDY, 1);
11684ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s);
11694ba25376SJoe Komlodi }
11704ba25376SJoe Komlodi }
11714ba25376SJoe Komlodi
aspeed_i3c_device_push_tx(AspeedI3CDevice * s,uint32_t val)11724ba25376SJoe Komlodi static void aspeed_i3c_device_push_tx(AspeedI3CDevice *s, uint32_t val)
11734ba25376SJoe Komlodi {
11744ba25376SJoe Komlodi if (fifo32_is_full(&s->tx_queue)) {
11754ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to push to TX FIFO when "
11764ba25376SJoe Komlodi "full\n", object_get_canonical_path(OBJECT(s)));
11774ba25376SJoe Komlodi return;
11784ba25376SJoe Komlodi }
11794ba25376SJoe Komlodi
11804ba25376SJoe Komlodi trace_aspeed_i3c_device_push_tx(s->id, val);
11814ba25376SJoe Komlodi fifo32_push(&s->tx_queue, val);
11824ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, TX_BUF_EMPTY_LOC,
11834ba25376SJoe Komlodi fifo32_num_free(&s->tx_queue));
11844ba25376SJoe Komlodi
11854ba25376SJoe Komlodi /* Threshold is 2^TX_BUF_THLD. */
11864ba25376SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, DATA_BUFFER_THLD_CTRL,
11874ba25376SJoe Komlodi TX_BUF_THLD);
11884ba25376SJoe Komlodi empty_threshold =
11894ba25376SJoe Komlodi aspeed_i3c_device_fifo_threshold_from_reg(empty_threshold);
11904ba25376SJoe Komlodi if (fifo32_num_free(&s->tx_queue) < empty_threshold) {
11914ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TX_THLD, 0);
11924ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s);
11934ba25376SJoe Komlodi }
11944ba25376SJoe Komlodi }
11954ba25376SJoe Komlodi
aspeed_i3c_device_pop_tx(AspeedI3CDevice * s)11964ba25376SJoe Komlodi static uint32_t aspeed_i3c_device_pop_tx(AspeedI3CDevice *s)
11974ba25376SJoe Komlodi {
11984ba25376SJoe Komlodi if (fifo32_is_empty(&s->tx_queue)) {
11994ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to pop from TX FIFO when "
12004ba25376SJoe Komlodi "empty\n", object_get_canonical_path(OBJECT(s)));
12014ba25376SJoe Komlodi return 0;
12024ba25376SJoe Komlodi }
12034ba25376SJoe Komlodi
12044ba25376SJoe Komlodi uint32_t val = fifo32_pop(&s->tx_queue);
12054ba25376SJoe Komlodi trace_aspeed_i3c_device_pop_tx(s->id, val);
12064ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, TX_BUF_EMPTY_LOC,
12074ba25376SJoe Komlodi fifo32_num_free(&s->tx_queue));
12084ba25376SJoe Komlodi
12094ba25376SJoe Komlodi /* Threshold is 2^TX_BUF_THLD. */
12104ba25376SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, DATA_BUFFER_THLD_CTRL,
12114ba25376SJoe Komlodi TX_BUF_THLD);
12124ba25376SJoe Komlodi empty_threshold =
12134ba25376SJoe Komlodi aspeed_i3c_device_fifo_threshold_from_reg(empty_threshold);
12144ba25376SJoe Komlodi if (fifo32_num_free(&s->tx_queue) >= empty_threshold) {
12154ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TX_THLD, 1);
12164ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s);
12174ba25376SJoe Komlodi }
12184ba25376SJoe Komlodi return val;
12194ba25376SJoe Komlodi }
12204ba25376SJoe Komlodi
aspeed_i3c_device_push_rx(AspeedI3CDevice * s,uint32_t val)12214ba25376SJoe Komlodi static void aspeed_i3c_device_push_rx(AspeedI3CDevice *s, uint32_t val)
12224ba25376SJoe Komlodi {
12234ba25376SJoe Komlodi if (fifo32_is_full(&s->rx_queue)) {
12244ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to push to RX FIFO when "
12254ba25376SJoe Komlodi "full\n", object_get_canonical_path(OBJECT(s)));
12264ba25376SJoe Komlodi return;
12274ba25376SJoe Komlodi }
12284ba25376SJoe Komlodi trace_aspeed_i3c_device_push_rx(s->id, val);
12294ba25376SJoe Komlodi fifo32_push(&s->rx_queue, val);
12304ba25376SJoe Komlodi
12314ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, RX_BUF_BLR,
12324ba25376SJoe Komlodi fifo32_num_used(&s->rx_queue));
12334ba25376SJoe Komlodi /* Threshold is 2^RX_BUF_THLD. */
12344ba25376SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, DATA_BUFFER_THLD_CTRL,
12354ba25376SJoe Komlodi RX_BUF_THLD);
12364ba25376SJoe Komlodi threshold = aspeed_i3c_device_fifo_threshold_from_reg(threshold);
12374ba25376SJoe Komlodi if (fifo32_num_used(&s->rx_queue) >= threshold) {
12384ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RX_THLD, 1);
12394ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s);
12404ba25376SJoe Komlodi }
12414ba25376SJoe Komlodi }
12424ba25376SJoe Komlodi
aspeed_i3c_device_short_transfer(AspeedI3CDevice * s,AspeedI3CTransferCmd cmd,AspeedI3CShortArg arg)12434ba25376SJoe Komlodi static void aspeed_i3c_device_short_transfer(AspeedI3CDevice *s,
12444ba25376SJoe Komlodi AspeedI3CTransferCmd cmd,
12454ba25376SJoe Komlodi AspeedI3CShortArg arg)
12464ba25376SJoe Komlodi {
12474ba25376SJoe Komlodi uint8_t err = ASPEED_I3C_RESP_QUEUE_ERR_NONE;
12484ba25376SJoe Komlodi uint8_t addr = aspeed_i3c_device_target_addr(s, cmd.dev_index);
12494ba25376SJoe Komlodi bool is_i2c = aspeed_i3c_device_target_is_i2c(s, cmd.dev_index);
12504ba25376SJoe Komlodi uint8_t data[4]; /* Max we can send on a short transfer is 4 bytes. */
12514ba25376SJoe Komlodi uint8_t len = 0;
12524ba25376SJoe Komlodi uint32_t bytes_sent; /* Ignored on short transfers. */
12534ba25376SJoe Komlodi
12544ba25376SJoe Komlodi /* Can't do reads on a short transfer. */
12554ba25376SJoe Komlodi if (cmd.rnw) {
12564ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Cannot do a read on a short "
12574ba25376SJoe Komlodi "transfer\n", object_get_canonical_path(OBJECT(s)));
12584ba25376SJoe Komlodi return;
12594ba25376SJoe Komlodi }
12604ba25376SJoe Komlodi
12614ba25376SJoe Komlodi if (aspeed_i3c_device_send_start(s, addr, /*is_recv=*/false, is_i2c)) {
12624ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_I2C_NACK;
12634ba25376SJoe Komlodi goto transfer_done;
12644ba25376SJoe Komlodi }
12654ba25376SJoe Komlodi
12664ba25376SJoe Komlodi /* Are we sending a command? */
12674ba25376SJoe Komlodi if (cmd.cp) {
12684ba25376SJoe Komlodi data[len] = cmd.cmd;
12694ba25376SJoe Komlodi len++;
12704ba25376SJoe Komlodi /*
12714ba25376SJoe Komlodi * byte0 is the defining byte for a command, and is only sent if a
12724ba25376SJoe Komlodi * command is present and if the command has a defining byte present.
12734ba25376SJoe Komlodi * (byte_strb & 0x01) is always treated as set by the controller, and is
12744ba25376SJoe Komlodi * ignored.
12754ba25376SJoe Komlodi */
12764ba25376SJoe Komlodi if (cmd.dbp) {
12774ba25376SJoe Komlodi data[len] += arg.byte0;
12784ba25376SJoe Komlodi len++;
12794ba25376SJoe Komlodi }
12804ba25376SJoe Komlodi }
12814ba25376SJoe Komlodi
12824ba25376SJoe Komlodi /* Send the bytes passed in the argument. */
12834ba25376SJoe Komlodi if (arg.byte_strb & 0x02) {
12844ba25376SJoe Komlodi data[len] = arg.byte1;
12854ba25376SJoe Komlodi len++;
12864ba25376SJoe Komlodi }
12874ba25376SJoe Komlodi if (arg.byte_strb & 0x04) {
12884ba25376SJoe Komlodi data[len] = arg.byte2;
12894ba25376SJoe Komlodi len++;
12904ba25376SJoe Komlodi }
12914ba25376SJoe Komlodi
12924ba25376SJoe Komlodi if (aspeed_i3c_device_send(s, data, len, &bytes_sent, is_i2c)) {
12934ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_I2C_NACK;
12944ba25376SJoe Komlodi } else {
12954ba25376SJoe Komlodi /* Only go to an idle state on a successful transfer. */
12964ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS,
12974ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_IDLE);
12984ba25376SJoe Komlodi }
12994ba25376SJoe Komlodi
13004ba25376SJoe Komlodi transfer_done:
13014ba25376SJoe Komlodi if (cmd.toc) {
13024ba25376SJoe Komlodi aspeed_i3c_device_end_transfer(s, is_i2c);
13034ba25376SJoe Komlodi }
13044ba25376SJoe Komlodi if (cmd.roc) {
13054ba25376SJoe Komlodi /*
13064ba25376SJoe Komlodi * ccc_type is always 0 in controller mode, data_len is 0 in short
13074ba25376SJoe Komlodi * transfers.
13084ba25376SJoe Komlodi */
13094ba25376SJoe Komlodi aspeed_i3c_device_resp_queue_push(s, err, cmd.tid, /*ccc_type=*/0,
13104ba25376SJoe Komlodi /*data_len=*/0);
13114ba25376SJoe Komlodi }
13124ba25376SJoe Komlodi }
13134ba25376SJoe Komlodi
13144ba25376SJoe Komlodi /* Returns number of bytes transmitted. */
aspeed_i3c_device_tx(AspeedI3CDevice * s,uint16_t num,bool is_i2c)13154ba25376SJoe Komlodi static uint16_t aspeed_i3c_device_tx(AspeedI3CDevice *s, uint16_t num,
13164ba25376SJoe Komlodi bool is_i2c)
13174ba25376SJoe Komlodi {
13184ba25376SJoe Komlodi uint16_t bytes_sent = 0;
13194ba25376SJoe Komlodi union {
13204ba25376SJoe Komlodi uint8_t b[sizeof(uint32_t)];
13214ba25376SJoe Komlodi uint32_t val;
13224ba25376SJoe Komlodi } val32;
13234ba25376SJoe Komlodi
13244ba25376SJoe Komlodi while (bytes_sent < num) {
13254ba25376SJoe Komlodi val32.val = aspeed_i3c_device_pop_tx(s);
13264ba25376SJoe Komlodi for (uint8_t i = 0; i < sizeof(val32.val); i++) {
13274ba25376SJoe Komlodi if (aspeed_i3c_device_send_byte(s, val32.b[i], is_i2c)) {
13284ba25376SJoe Komlodi return bytes_sent;
13294ba25376SJoe Komlodi }
13304ba25376SJoe Komlodi bytes_sent++;
13314ba25376SJoe Komlodi
13324ba25376SJoe Komlodi /* We're not sending the full 32-bits, break early. */
13334ba25376SJoe Komlodi if (bytes_sent >= num) {
13344ba25376SJoe Komlodi break;
13354ba25376SJoe Komlodi }
13364ba25376SJoe Komlodi }
13374ba25376SJoe Komlodi }
13384ba25376SJoe Komlodi
13394ba25376SJoe Komlodi return bytes_sent;
13404ba25376SJoe Komlodi }
13414ba25376SJoe Komlodi
13424ba25376SJoe Komlodi /* Returns number of bytes received. */
aspeed_i3c_device_rx(AspeedI3CDevice * s,uint16_t num,bool is_i2c)13434ba25376SJoe Komlodi static uint16_t aspeed_i3c_device_rx(AspeedI3CDevice *s, uint16_t num,
13444ba25376SJoe Komlodi bool is_i2c)
13454ba25376SJoe Komlodi {
13464ba25376SJoe Komlodi /*
13474ba25376SJoe Komlodi * Allocate a temporary buffer to read data from the target.
13484ba25376SJoe Komlodi * Zero it and word-align it as well in case we're reading unaligned data.
13494ba25376SJoe Komlodi */
13504ba25376SJoe Komlodi g_autofree uint8_t *data = g_new0(uint8_t, num + (num & 0x03));
13514ba25376SJoe Komlodi uint32_t *data32 = (uint32_t *)data;
13524ba25376SJoe Komlodi /*
13534ba25376SJoe Komlodi * 32-bits since the I3C API wants a 32-bit number, even though the
13544ba25376SJoe Komlodi * controller can only do 16-bit transfers.
13554ba25376SJoe Komlodi */
13564ba25376SJoe Komlodi uint32_t num_read = 0;
13574ba25376SJoe Komlodi
13584ba25376SJoe Komlodi /* Can NACK if the target receives an unsupported CCC. */
13594ba25376SJoe Komlodi if (aspeed_i3c_device_recv_data(s, is_i2c, data, num, &num_read)) {
13604ba25376SJoe Komlodi return 0;
13614ba25376SJoe Komlodi }
13624ba25376SJoe Komlodi
13634ba25376SJoe Komlodi for (uint16_t i = 0; i < num_read / 4; i++) {
13644ba25376SJoe Komlodi aspeed_i3c_device_push_rx(s, *data32);
13654ba25376SJoe Komlodi data32++;
13664ba25376SJoe Komlodi }
13674ba25376SJoe Komlodi /*
13684ba25376SJoe Komlodi * If we're pushing data that isn't 32-bit aligned, push what's left.
13694ba25376SJoe Komlodi * It's software's responsibility to know what bits are valid in the partial
13704ba25376SJoe Komlodi * data.
13714ba25376SJoe Komlodi */
13724ba25376SJoe Komlodi if (num_read & 0x03) {
13734ba25376SJoe Komlodi aspeed_i3c_device_push_rx(s, *data32);
13744ba25376SJoe Komlodi }
13754ba25376SJoe Komlodi
13764ba25376SJoe Komlodi return num_read;
13774ba25376SJoe Komlodi }
13784ba25376SJoe Komlodi
aspeed_i3c_device_transfer_ccc(AspeedI3CDevice * s,AspeedI3CTransferCmd cmd,AspeedI3CTransferArg arg)13794ba25376SJoe Komlodi static int aspeed_i3c_device_transfer_ccc(AspeedI3CDevice *s,
13804ba25376SJoe Komlodi AspeedI3CTransferCmd cmd,
13814ba25376SJoe Komlodi AspeedI3CTransferArg arg)
13824ba25376SJoe Komlodi {
13834ba25376SJoe Komlodi /* CCC start is always a write. CCCs cannot be done on I2C devices. */
13844ba25376SJoe Komlodi if (aspeed_i3c_device_send_start(s, I3C_BROADCAST, /*is_recv=*/false,
13854ba25376SJoe Komlodi /*is_i2c=*/false)) {
13864ba25376SJoe Komlodi return ASPEED_I3C_RESP_QUEUE_ERR_BROADCAST_NACK;
13874ba25376SJoe Komlodi }
13884ba25376SJoe Komlodi trace_aspeed_i3c_device_transfer_ccc(s->id, cmd.cmd);
13894ba25376SJoe Komlodi if (aspeed_i3c_device_send_byte(s, cmd.cmd, /*is_i2c=*/false)) {
13904ba25376SJoe Komlodi return ASPEED_I3C_RESP_QUEUE_ERR_I2C_NACK;
13914ba25376SJoe Komlodi }
13924ba25376SJoe Komlodi
13934ba25376SJoe Komlodi /* On a direct CCC, we do a restart and then send the target's address. */
13944ba25376SJoe Komlodi if (CCC_IS_DIRECT(cmd.cmd)) {
13954ba25376SJoe Komlodi bool is_recv = cmd.rnw;
13964ba25376SJoe Komlodi uint8_t addr = aspeed_i3c_device_target_addr(s, cmd.dev_index);
13974ba25376SJoe Komlodi if (aspeed_i3c_device_send_start(s, addr, is_recv, /*is_i2c=*/false)) {
13984ba25376SJoe Komlodi return ASPEED_I3C_RESP_QUEUE_ERR_BROADCAST_NACK;
13994ba25376SJoe Komlodi }
14004ba25376SJoe Komlodi }
14014ba25376SJoe Komlodi
14024ba25376SJoe Komlodi return ASPEED_I3C_RESP_QUEUE_ERR_NONE;
14034ba25376SJoe Komlodi }
14044ba25376SJoe Komlodi
aspeed_i3c_device_transfer(AspeedI3CDevice * s,AspeedI3CTransferCmd cmd,AspeedI3CTransferArg arg)14054ba25376SJoe Komlodi static void aspeed_i3c_device_transfer(AspeedI3CDevice *s,
14064ba25376SJoe Komlodi AspeedI3CTransferCmd cmd,
14074ba25376SJoe Komlodi AspeedI3CTransferArg arg)
14084ba25376SJoe Komlodi {
14094ba25376SJoe Komlodi bool is_recv = cmd.rnw;
14104ba25376SJoe Komlodi uint8_t err = ASPEED_I3C_RESP_QUEUE_ERR_NONE;
14114ba25376SJoe Komlodi uint8_t addr = aspeed_i3c_device_target_addr(s, cmd.dev_index);
14124ba25376SJoe Komlodi bool is_i2c = aspeed_i3c_device_target_is_i2c(s, cmd.dev_index);
14134ba25376SJoe Komlodi uint16_t bytes_transferred = 0;
14144ba25376SJoe Komlodi
14154ba25376SJoe Komlodi if (cmd.cp) {
14164ba25376SJoe Komlodi /* We're sending a CCC. */
14174ba25376SJoe Komlodi err = aspeed_i3c_device_transfer_ccc(s, cmd, arg);
14184ba25376SJoe Komlodi if (err != ASPEED_I3C_RESP_QUEUE_ERR_NONE) {
14194ba25376SJoe Komlodi goto transfer_done;
14204ba25376SJoe Komlodi }
14214ba25376SJoe Komlodi } else {
14224ba25376SJoe Komlodi if (ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL, I3C_BROADCAST_ADDR_INC) &&
14234ba25376SJoe Komlodi is_i2c == false) {
14244ba25376SJoe Komlodi if (aspeed_i3c_device_send_start(s, I3C_BROADCAST,
14254ba25376SJoe Komlodi /*is_recv=*/false, is_i2c)) {
14264ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_I2C_NACK;
14274ba25376SJoe Komlodi goto transfer_done;
14284ba25376SJoe Komlodi }
14294ba25376SJoe Komlodi }
14304ba25376SJoe Komlodi /* Otherwise we're doing a private transfer. */
14314ba25376SJoe Komlodi if (aspeed_i3c_device_send_start(s, addr, is_recv, is_i2c)) {
14324ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_I2C_NACK;
14334ba25376SJoe Komlodi goto transfer_done;
14344ba25376SJoe Komlodi }
14354ba25376SJoe Komlodi }
14364ba25376SJoe Komlodi
14374ba25376SJoe Komlodi if (is_recv) {
14384ba25376SJoe Komlodi bytes_transferred = aspeed_i3c_device_rx(s, arg.data_len, is_i2c);
14394ba25376SJoe Komlodi } else {
14404ba25376SJoe Komlodi bytes_transferred = aspeed_i3c_device_tx(s, arg.data_len, is_i2c);
14414ba25376SJoe Komlodi }
14424ba25376SJoe Komlodi
14434ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS,
14444ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_IDLE);
14454ba25376SJoe Komlodi
14464ba25376SJoe Komlodi transfer_done:
14474ba25376SJoe Komlodi if (cmd.toc) {
14484ba25376SJoe Komlodi aspeed_i3c_device_end_transfer(s, is_i2c);
14494ba25376SJoe Komlodi }
14504ba25376SJoe Komlodi if (cmd.roc) {
14514ba25376SJoe Komlodi /*
14524ba25376SJoe Komlodi * data_len is the number of bytes that still need to be TX'd, or the
14534ba25376SJoe Komlodi * number of bytes RX'd.
14544ba25376SJoe Komlodi */
14554ba25376SJoe Komlodi uint16_t data_len = is_recv ? bytes_transferred : arg.data_len -
14564ba25376SJoe Komlodi bytes_transferred;
14574ba25376SJoe Komlodi /* CCCT is always 0 in controller mode. */
14584ba25376SJoe Komlodi aspeed_i3c_device_resp_queue_push(s, err, cmd.tid, /*ccc_type=*/0,
14594ba25376SJoe Komlodi data_len);
14604ba25376SJoe Komlodi }
14614ba25376SJoe Komlodi
14624ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s);
14634ba25376SJoe Komlodi }
14644ba25376SJoe Komlodi
aspeed_i3c_device_transfer_cmd(AspeedI3CDevice * s,AspeedI3CTransferCmd cmd,AspeedI3CCmdQueueData arg)14654ba25376SJoe Komlodi static void aspeed_i3c_device_transfer_cmd(AspeedI3CDevice *s,
14664ba25376SJoe Komlodi AspeedI3CTransferCmd cmd,
14674ba25376SJoe Komlodi AspeedI3CCmdQueueData arg)
14684ba25376SJoe Komlodi {
14694ba25376SJoe Komlodi uint8_t arg_attr = FIELD_EX32(arg.word, COMMAND_QUEUE_PORT, CMD_ATTR);
14704ba25376SJoe Komlodi
14714ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CMD_TID, cmd.tid);
14724ba25376SJoe Komlodi
14734ba25376SJoe Komlodi /* User is trying to do HDR transfers, see if we can do them. */
14744ba25376SJoe Komlodi if (cmd.speed == 0x06 && !aspeed_i3c_device_has_hdr_ddr(s)) {
14754ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: HDR DDR is not supported\n",
14764ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s)));
14774ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS,
14784ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_HALT);
14794ba25376SJoe Komlodi return;
14804ba25376SJoe Komlodi }
14814ba25376SJoe Komlodi if (cmd.speed == 0x05 && !aspeed_i3c_device_has_hdr_ts(s)) {
14824ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: HDR TS is not supported\n",
14834ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s)));
14844ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS,
14854ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_HALT);
14864ba25376SJoe Komlodi return;
14874ba25376SJoe Komlodi }
14884ba25376SJoe Komlodi
14894ba25376SJoe Komlodi if (arg_attr == ASPEED_I3C_CMD_ATTR_TRANSFER_ARG) {
14904ba25376SJoe Komlodi aspeed_i3c_device_transfer(s, cmd, arg.transfer_arg);
14914ba25376SJoe Komlodi } else if (arg_attr == ASPEED_I3C_CMD_ATTR_SHORT_DATA_ARG) {
14924ba25376SJoe Komlodi aspeed_i3c_device_short_transfer(s, cmd, arg.short_arg);
14934ba25376SJoe Komlodi } else {
14944ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Unknown command queue cmd_attr 0x%x"
14954ba25376SJoe Komlodi "\n", object_get_canonical_path(OBJECT(s)), arg_attr);
14964ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS,
14974ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_HALT);
14984ba25376SJoe Komlodi }
14994ba25376SJoe Komlodi }
15004ba25376SJoe Komlodi
aspeed_i3c_device_update_char_table(AspeedI3CDevice * s,uint8_t offset,uint64_t pid,uint8_t bcr,uint8_t dcr,uint8_t addr)15014ba25376SJoe Komlodi static void aspeed_i3c_device_update_char_table(AspeedI3CDevice *s,
15024ba25376SJoe Komlodi uint8_t offset, uint64_t pid,
15034ba25376SJoe Komlodi uint8_t bcr, uint8_t dcr,
15044ba25376SJoe Komlodi uint8_t addr)
15054ba25376SJoe Komlodi {
15064ba25376SJoe Komlodi if (offset > ASPEED_I3C_NR_DEVICES) {
15074ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Device char table offset %d out of "
15084ba25376SJoe Komlodi "bounds\n", object_get_canonical_path(OBJECT(s)), offset);
15094ba25376SJoe Komlodi /* If we're out of bounds, do nothing. */
15104ba25376SJoe Komlodi return;
15114ba25376SJoe Komlodi }
15124ba25376SJoe Komlodi
15134ba25376SJoe Komlodi /* Each char table index is 128 bits apart. */
15144ba25376SJoe Komlodi uint16_t dev_index = R_DEVICE_CHARACTERISTIC_TABLE_LOC1 + offset *
15154ba25376SJoe Komlodi sizeof(uint32_t);
15164ba25376SJoe Komlodi s->regs[dev_index] = pid & 0xffffffff;
15174ba25376SJoe Komlodi pid >>= 32;
15184ba25376SJoe Komlodi s->regs[dev_index + 1] = FIELD_DP32(s->regs[dev_index + 1],
15194ba25376SJoe Komlodi DEVICE_CHARACTERISTIC_TABLE_LOC2,
15204ba25376SJoe Komlodi MSB_PID, pid);
15214ba25376SJoe Komlodi s->regs[dev_index + 2] = FIELD_DP32(s->regs[dev_index + 2],
15224ba25376SJoe Komlodi DEVICE_CHARACTERISTIC_TABLE_LOC3, DCR,
15234ba25376SJoe Komlodi dcr);
15244ba25376SJoe Komlodi s->regs[dev_index + 2] = FIELD_DP32(s->regs[dev_index + 2],
15254ba25376SJoe Komlodi DEVICE_CHARACTERISTIC_TABLE_LOC3, BCR,
15264ba25376SJoe Komlodi bcr);
15274ba25376SJoe Komlodi s->regs[dev_index + 3] = FIELD_DP32(s->regs[dev_index + 3],
15284ba25376SJoe Komlodi DEVICE_CHARACTERISTIC_TABLE_LOC4,
15294ba25376SJoe Komlodi DEV_DYNAMIC_ADDR, addr);
15304ba25376SJoe Komlodi
15314ba25376SJoe Komlodi /* Increment PRESENT_DEV_CHAR_TABLE_INDEX. */
15324ba25376SJoe Komlodi uint8_t idx = ARRAY_FIELD_EX32(s->regs, DEV_CHAR_TABLE_POINTER,
15334ba25376SJoe Komlodi PRESENT_DEV_CHAR_TABLE_INDEX);
15344ba25376SJoe Komlodi /* Increment and rollover. */
15354ba25376SJoe Komlodi idx++;
15364ba25376SJoe Komlodi if (idx >= ARRAY_FIELD_EX32(s->regs, DEV_CHAR_TABLE_POINTER,
15374ba25376SJoe Komlodi DEV_CHAR_TABLE_DEPTH) / 4) {
15384ba25376SJoe Komlodi idx = 0;
15394ba25376SJoe Komlodi }
15404ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEV_CHAR_TABLE_POINTER,
15414ba25376SJoe Komlodi PRESENT_DEV_CHAR_TABLE_INDEX, idx);
15424ba25376SJoe Komlodi }
15434ba25376SJoe Komlodi
aspeed_i3c_device_addr_assign_cmd(AspeedI3CDevice * s,AspeedI3CAddrAssignCmd cmd)15444ba25376SJoe Komlodi static void aspeed_i3c_device_addr_assign_cmd(AspeedI3CDevice *s,
15454ba25376SJoe Komlodi AspeedI3CAddrAssignCmd cmd)
15464ba25376SJoe Komlodi {
15474ba25376SJoe Komlodi uint8_t i = 0;
15484ba25376SJoe Komlodi uint8_t err = ASPEED_I3C_RESP_QUEUE_ERR_NONE;
15494ba25376SJoe Komlodi
15504ba25376SJoe Komlodi if (!aspeed_i3c_device_has_entdaa(s)) {
15514ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: ENTDAA is not supported\n",
15524ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s)));
15534ba25376SJoe Komlodi return;
15544ba25376SJoe Komlodi }
15554ba25376SJoe Komlodi
15564ba25376SJoe Komlodi /* Tell everyone to ENTDAA. If these error, no one is on the bus. */
15574ba25376SJoe Komlodi if (aspeed_i3c_device_send_start(s, I3C_BROADCAST, /*is_recv=*/false,
15584ba25376SJoe Komlodi /*is_i2c=*/false)) {
15594ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_BROADCAST_NACK;
15604ba25376SJoe Komlodi goto transfer_done;
15614ba25376SJoe Komlodi }
15624ba25376SJoe Komlodi if (aspeed_i3c_device_send_byte(s, cmd.cmd, /*is_i2c=*/false)) {
15634ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_BROADCAST_NACK;
15644ba25376SJoe Komlodi goto transfer_done;
15654ba25376SJoe Komlodi }
15664ba25376SJoe Komlodi
15674ba25376SJoe Komlodi /* Go through each device in the table and assign it an address. */
15684ba25376SJoe Komlodi for (i = 0; i < cmd.dev_count; i++) {
15694ba25376SJoe Komlodi uint8_t addr = aspeed_i3c_device_target_addr(s, cmd.dev_index + i);
15704ba25376SJoe Komlodi union {
15714ba25376SJoe Komlodi uint64_t pid:48;
15724ba25376SJoe Komlodi uint8_t bcr;
15734ba25376SJoe Komlodi uint8_t dcr;
15744ba25376SJoe Komlodi uint32_t w[2];
15754ba25376SJoe Komlodi uint8_t b[8];
15764ba25376SJoe Komlodi } target_info;
15774ba25376SJoe Komlodi
15784ba25376SJoe Komlodi /* If this fails, there was no one left to ENTDAA. */
15794ba25376SJoe Komlodi if (aspeed_i3c_device_send_start(s, I3C_BROADCAST, /*is_recv=*/false,
15804ba25376SJoe Komlodi /*is_i2c=*/false)) {
15814ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_BROADCAST_NACK;
15824ba25376SJoe Komlodi break;
15834ba25376SJoe Komlodi }
15844ba25376SJoe Komlodi
15854ba25376SJoe Komlodi /*
15864ba25376SJoe Komlodi * In ENTDAA, we read 8 bytes from the target, which will be the
15874ba25376SJoe Komlodi * target's PID, BCR, and DCR. After that, we send it the dynamic
15884ba25376SJoe Komlodi * address.
15894ba25376SJoe Komlodi * Don't bother checking the number of bytes received, it must send 8
15904ba25376SJoe Komlodi * bytes during ENTDAA.
15914ba25376SJoe Komlodi */
15924ba25376SJoe Komlodi uint32_t num_read;
15934ba25376SJoe Komlodi if (aspeed_i3c_device_recv_data(s, /*is_i2c=*/false, target_info.b,
15944ba25376SJoe Komlodi I3C_ENTDAA_SIZE, &num_read)) {
15954ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Target NACKed ENTDAA CCC\n",
15964ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s)));
15974ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_DAA_NACK;
15984ba25376SJoe Komlodi goto transfer_done;
15994ba25376SJoe Komlodi }
16004ba25376SJoe Komlodi if (aspeed_i3c_device_send_byte(s, addr, /*is_i2c=*/false)) {
16014ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Target NACKed addr 0x%.2x "
16024ba25376SJoe Komlodi "during ENTDAA\n",
16034ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s)), addr);
16044ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_DAA_NACK;
16054ba25376SJoe Komlodi break;
16064ba25376SJoe Komlodi }
16074ba25376SJoe Komlodi aspeed_i3c_device_update_char_table(s, cmd.dev_index + i,
16084ba25376SJoe Komlodi target_info.pid, target_info.bcr,
16094ba25376SJoe Komlodi target_info.dcr, addr);
16104ba25376SJoe Komlodi
16114ba25376SJoe Komlodi /* Push the PID, BCR, and DCR to the RX queue. */
16124ba25376SJoe Komlodi aspeed_i3c_device_push_rx(s, target_info.w[0]);
16134ba25376SJoe Komlodi aspeed_i3c_device_push_rx(s, target_info.w[1]);
16144ba25376SJoe Komlodi }
16154ba25376SJoe Komlodi
16164ba25376SJoe Komlodi transfer_done:
16174ba25376SJoe Komlodi /* Do we send a STOP? */
16184ba25376SJoe Komlodi if (cmd.toc) {
16194ba25376SJoe Komlodi aspeed_i3c_device_end_transfer(s, /*is_i2c=*/false);
16204ba25376SJoe Komlodi }
16214ba25376SJoe Komlodi /*
16224ba25376SJoe Komlodi * For addr assign commands, the length field is the number of devices
16234ba25376SJoe Komlodi * left to assign. CCCT is always 0 in controller mode.
16244ba25376SJoe Komlodi */
16254ba25376SJoe Komlodi if (cmd.roc) {
16264ba25376SJoe Komlodi aspeed_i3c_device_resp_queue_push(s, err, cmd.tid, /*ccc_type=*/0,
16274ba25376SJoe Komlodi cmd.dev_count - i);
16284ba25376SJoe Komlodi }
16294ba25376SJoe Komlodi }
16304ba25376SJoe Komlodi
aspeed_i3c_device_cmd_queue_pop(AspeedI3CDevice * s)16314ba25376SJoe Komlodi static uint32_t aspeed_i3c_device_cmd_queue_pop(AspeedI3CDevice *s)
16324ba25376SJoe Komlodi {
16334ba25376SJoe Komlodi if (fifo32_is_empty(&s->cmd_queue)) {
16344ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to dequeue command queue "
16354ba25376SJoe Komlodi "when it was empty\n",
16364ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s)));
16374ba25376SJoe Komlodi return 0;
16384ba25376SJoe Komlodi }
16394ba25376SJoe Komlodi uint32_t val = fifo32_pop(&s->cmd_queue);
16404ba25376SJoe Komlodi
16414ba25376SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL,
16424ba25376SJoe Komlodi CMD_BUF_EMPTY_THLD);
16434ba25376SJoe Komlodi uint8_t cmd_queue_empty_loc = ARRAY_FIELD_EX32(s->regs,
16444ba25376SJoe Komlodi QUEUE_STATUS_LEVEL,
16454ba25376SJoe Komlodi CMD_QUEUE_EMPTY_LOC);
16464ba25376SJoe Komlodi cmd_queue_empty_loc++;
16474ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, CMD_QUEUE_EMPTY_LOC,
16484ba25376SJoe Komlodi cmd_queue_empty_loc);
16494ba25376SJoe Komlodi if (cmd_queue_empty_loc >= empty_threshold) {
16504ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, CMD_QUEUE_RDY, 1);
16514ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s);
16524ba25376SJoe Komlodi }
16534ba25376SJoe Komlodi
16544ba25376SJoe Komlodi return val;
16554ba25376SJoe Komlodi }
16564ba25376SJoe Komlodi
aspeed_i3c_device_cmd_queue_execute(AspeedI3CDevice * s)16574ba25376SJoe Komlodi static void aspeed_i3c_device_cmd_queue_execute(AspeedI3CDevice *s)
16584ba25376SJoe Komlodi {
16594ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS,
16604ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_IDLE);
16614ba25376SJoe Komlodi if (!aspeed_i3c_device_can_transmit(s)) {
16624ba25376SJoe Komlodi return;
16634ba25376SJoe Komlodi }
16644ba25376SJoe Komlodi
16654ba25376SJoe Komlodi /*
16664ba25376SJoe Komlodi * We only start executing when a command is passed into the FIFO.
16674ba25376SJoe Komlodi * We expect there to be a multiple of 2 items in the queue. The first item
16684ba25376SJoe Komlodi * should be an argument to a command, and the command should be the second
16694ba25376SJoe Komlodi * item.
16704ba25376SJoe Komlodi */
16714ba25376SJoe Komlodi if (fifo32_num_used(&s->cmd_queue) & 1) {
16724ba25376SJoe Komlodi return;
16734ba25376SJoe Komlodi }
16744ba25376SJoe Komlodi
16754ba25376SJoe Komlodi while (!fifo32_is_empty(&s->cmd_queue)) {
16764ba25376SJoe Komlodi AspeedI3CCmdQueueData arg;
16774ba25376SJoe Komlodi arg.word = aspeed_i3c_device_cmd_queue_pop(s);
16784ba25376SJoe Komlodi AspeedI3CCmdQueueData cmd;
16794ba25376SJoe Komlodi cmd.word = aspeed_i3c_device_cmd_queue_pop(s);
16804ba25376SJoe Komlodi trace_aspeed_i3c_device_cmd_queue_execute(s->id, cmd.word, arg.word);
16814ba25376SJoe Komlodi
16824ba25376SJoe Komlodi uint8_t cmd_attr = FIELD_EX32(cmd.word, COMMAND_QUEUE_PORT, CMD_ATTR);
16834ba25376SJoe Komlodi switch (cmd_attr) {
16844ba25376SJoe Komlodi case ASPEED_I3C_CMD_ATTR_TRANSFER_CMD:
16854ba25376SJoe Komlodi aspeed_i3c_device_transfer_cmd(s, cmd.transfer_cmd, arg);
16864ba25376SJoe Komlodi break;
16874ba25376SJoe Komlodi case ASPEED_I3C_CMD_ATTR_ADDR_ASSIGN_CMD:
16884ba25376SJoe Komlodi /* Arg is discarded for addr assign commands. */
16894ba25376SJoe Komlodi aspeed_i3c_device_addr_assign_cmd(s, cmd.addr_assign_cmd);
16904ba25376SJoe Komlodi break;
16914ba25376SJoe Komlodi case ASPEED_I3C_CMD_ATTR_TRANSFER_ARG:
16924ba25376SJoe Komlodi case ASPEED_I3C_CMD_ATTR_SHORT_DATA_ARG:
16934ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Command queue received argument"
16944ba25376SJoe Komlodi " packet when it expected a command packet\n",
16954ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s)));
16964ba25376SJoe Komlodi break;
16974ba25376SJoe Komlodi default:
16984ba25376SJoe Komlodi /*
16994ba25376SJoe Komlodi * The caller's check before queueing an item should prevent this
17004ba25376SJoe Komlodi * from happening.
17014ba25376SJoe Komlodi */
17024ba25376SJoe Komlodi g_assert_not_reached();
17034ba25376SJoe Komlodi break;
17044ba25376SJoe Komlodi }
17054ba25376SJoe Komlodi }
17064ba25376SJoe Komlodi }
17074ba25376SJoe Komlodi
aspeed_i3c_device_cmd_queue_push(AspeedI3CDevice * s,uint32_t val)17084ba25376SJoe Komlodi static void aspeed_i3c_device_cmd_queue_push(AspeedI3CDevice *s, uint32_t val)
17094ba25376SJoe Komlodi {
17104ba25376SJoe Komlodi if (fifo32_is_full(&s->cmd_queue)) {
17114ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Command queue received packet when "
17124ba25376SJoe Komlodi "already full\n", object_get_canonical_path(OBJECT(s)));
17134ba25376SJoe Komlodi return;
17144ba25376SJoe Komlodi }
17154ba25376SJoe Komlodi trace_aspeed_i3c_device_cmd_queue_push(s->id, val);
17164ba25376SJoe Komlodi fifo32_push(&s->cmd_queue, val);
17174ba25376SJoe Komlodi
17184ba25376SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL,
17194ba25376SJoe Komlodi CMD_BUF_EMPTY_THLD);
17204ba25376SJoe Komlodi uint8_t cmd_queue_empty_loc = ARRAY_FIELD_EX32(s->regs,
17214ba25376SJoe Komlodi QUEUE_STATUS_LEVEL,
17224ba25376SJoe Komlodi CMD_QUEUE_EMPTY_LOC);
17234ba25376SJoe Komlodi if (cmd_queue_empty_loc) {
17244ba25376SJoe Komlodi cmd_queue_empty_loc--;
17254ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, CMD_QUEUE_EMPTY_LOC,
17264ba25376SJoe Komlodi cmd_queue_empty_loc);
17274ba25376SJoe Komlodi }
17284ba25376SJoe Komlodi if (cmd_queue_empty_loc < empty_threshold) {
17294ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, CMD_QUEUE_RDY, 0);
17304ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s);
17314ba25376SJoe Komlodi }
17324ba25376SJoe Komlodi }
17334ba25376SJoe Komlodi
aspeed_i3c_device_cmd_queue_port_w(AspeedI3CDevice * s,uint32_t val)17344ba25376SJoe Komlodi static void aspeed_i3c_device_cmd_queue_port_w(AspeedI3CDevice *s, uint32_t val)
17354ba25376SJoe Komlodi {
17364ba25376SJoe Komlodi uint8_t cmd_attr = FIELD_EX32(val, COMMAND_QUEUE_PORT, CMD_ATTR);
17374ba25376SJoe Komlodi
17384ba25376SJoe Komlodi switch (cmd_attr) {
17394ba25376SJoe Komlodi /* If a command is received we can start executing it. */
17404ba25376SJoe Komlodi case ASPEED_I3C_CMD_ATTR_TRANSFER_CMD:
17414ba25376SJoe Komlodi case ASPEED_I3C_CMD_ATTR_ADDR_ASSIGN_CMD:
17424ba25376SJoe Komlodi aspeed_i3c_device_cmd_queue_push(s, val);
17434ba25376SJoe Komlodi aspeed_i3c_device_cmd_queue_execute(s);
17444ba25376SJoe Komlodi break;
17454ba25376SJoe Komlodi /* If we get an argument just push it. */
17464ba25376SJoe Komlodi case ASPEED_I3C_CMD_ATTR_TRANSFER_ARG:
17474ba25376SJoe Komlodi case ASPEED_I3C_CMD_ATTR_SHORT_DATA_ARG:
17484ba25376SJoe Komlodi aspeed_i3c_device_cmd_queue_push(s, val);
17494ba25376SJoe Komlodi break;
17504ba25376SJoe Komlodi default:
17514ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Command queue received packet with "
17524ba25376SJoe Komlodi "unknown cmd attr 0x%x\n",
17534ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s)), cmd_attr);
17544ba25376SJoe Komlodi break;
17554ba25376SJoe Komlodi }
17564ba25376SJoe Komlodi }
17574ba25376SJoe Komlodi
aspeed_i3c_device_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)17587d87775fSJoe Komlodi static void aspeed_i3c_device_write(void *opaque, hwaddr offset,
17597d87775fSJoe Komlodi uint64_t value, unsigned size)
17607d87775fSJoe Komlodi {
17617d87775fSJoe Komlodi AspeedI3CDevice *s = ASPEED_I3C_DEVICE(opaque);
17627d87775fSJoe Komlodi uint32_t addr = offset >> 2;
176397fb7498SJoe Komlodi uint32_t val32 = (uint32_t)value;
17647d87775fSJoe Komlodi
17657d87775fSJoe Komlodi trace_aspeed_i3c_device_write(s->id, offset, value);
17667d87775fSJoe Komlodi
176797fb7498SJoe Komlodi val32 &= ~ast2600_i3c_device_ro[addr];
17687d87775fSJoe Komlodi switch (addr) {
17697d87775fSJoe Komlodi case R_HW_CAPABILITY:
17707d87775fSJoe Komlodi case R_RESPONSE_QUEUE_PORT:
17717d87775fSJoe Komlodi case R_IBI_QUEUE_DATA:
17727d87775fSJoe Komlodi case R_QUEUE_STATUS_LEVEL:
17737d87775fSJoe Komlodi case R_PRESENT_STATE:
17747d87775fSJoe Komlodi case R_CCC_DEVICE_STATUS:
17757d87775fSJoe Komlodi case R_DEVICE_ADDR_TABLE_POINTER:
17767d87775fSJoe Komlodi case R_VENDOR_SPECIFIC_REG_POINTER:
17777d87775fSJoe Komlodi case R_SLV_CHAR_CTRL:
17787d87775fSJoe Komlodi case R_SLV_MAX_LEN:
17797d87775fSJoe Komlodi case R_MAX_READ_TURNAROUND:
17807d87775fSJoe Komlodi case R_I3C_VER_ID:
17817d87775fSJoe Komlodi case R_I3C_VER_TYPE:
17827d87775fSJoe Komlodi case R_EXTENDED_CAPABILITY:
17837d87775fSJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR,
17847d87775fSJoe Komlodi "%s: write to readonly register[0x%02" HWADDR_PRIx
17857d87775fSJoe Komlodi "] = 0x%08" PRIx64 "\n",
17867d87775fSJoe Komlodi __func__, offset, value);
17877d87775fSJoe Komlodi break;
1788eee51e8fSJoe Komlodi case R_DEVICE_CTRL:
1789eee51e8fSJoe Komlodi aspeed_i3c_device_ctrl_w(s, val32);
1790eee51e8fSJoe Komlodi break;
17917d87775fSJoe Komlodi case R_RX_TX_DATA_PORT:
17924ba25376SJoe Komlodi aspeed_i3c_device_push_tx(s, val32);
17934ba25376SJoe Komlodi break;
17944ba25376SJoe Komlodi case R_COMMAND_QUEUE_PORT:
17954ba25376SJoe Komlodi aspeed_i3c_device_cmd_queue_port_w(s, val32);
17967d87775fSJoe Komlodi break;
17977d87775fSJoe Komlodi case R_RESET_CTRL:
1798*66ae8f22SJoe Komlodi aspeed_i3c_device_reset_ctrl_w(s, val32);
17997d87775fSJoe Komlodi break;
18003816bedaSJoe Komlodi case R_INTR_STATUS:
18013816bedaSJoe Komlodi aspeed_i3c_device_intr_status_w(s, val32);
18023816bedaSJoe Komlodi break;
18033816bedaSJoe Komlodi case R_INTR_STATUS_EN:
18043816bedaSJoe Komlodi aspeed_i3c_device_intr_status_en_w(s, val32);
18053816bedaSJoe Komlodi break;
18063816bedaSJoe Komlodi case R_INTR_SIGNAL_EN:
18073816bedaSJoe Komlodi aspeed_i3c_device_intr_signal_en_w(s, val32);
18083816bedaSJoe Komlodi break;
18093816bedaSJoe Komlodi case R_INTR_FORCE:
18103816bedaSJoe Komlodi aspeed_i3c_device_intr_force_w(s, val32);
18113816bedaSJoe Komlodi break;
18127d87775fSJoe Komlodi default:
181397fb7498SJoe Komlodi s->regs[addr] = val32;
18147d87775fSJoe Komlodi break;
18157d87775fSJoe Komlodi }
18167d87775fSJoe Komlodi }
18177d87775fSJoe Komlodi
18187d87775fSJoe Komlodi static const VMStateDescription aspeed_i3c_device_vmstate = {
18197d87775fSJoe Komlodi .name = TYPE_ASPEED_I3C,
18207d87775fSJoe Komlodi .version_id = 1,
18217d87775fSJoe Komlodi .minimum_version_id = 1,
18227d87775fSJoe Komlodi .fields = (const VMStateField[]){
18237d87775fSJoe Komlodi VMSTATE_UINT32_ARRAY(regs, AspeedI3CDevice, ASPEED_I3C_DEVICE_NR_REGS),
18247d87775fSJoe Komlodi VMSTATE_END_OF_LIST(),
18257d87775fSJoe Komlodi }
18267d87775fSJoe Komlodi };
18277d87775fSJoe Komlodi
18287d87775fSJoe Komlodi static const MemoryRegionOps aspeed_i3c_device_ops = {
18297d87775fSJoe Komlodi .read = aspeed_i3c_device_read,
18307d87775fSJoe Komlodi .write = aspeed_i3c_device_write,
18317d87775fSJoe Komlodi .endianness = DEVICE_LITTLE_ENDIAN,
18327d87775fSJoe Komlodi };
18337d87775fSJoe Komlodi
aspeed_i3c_device_realize(DeviceState * dev,Error ** errp)18347d87775fSJoe Komlodi static void aspeed_i3c_device_realize(DeviceState *dev, Error **errp)
18357d87775fSJoe Komlodi {
18367d87775fSJoe Komlodi AspeedI3CDevice *s = ASPEED_I3C_DEVICE(dev);
18377d87775fSJoe Komlodi g_autofree char *name = g_strdup_printf(TYPE_ASPEED_I3C_DEVICE ".%d",
18387d87775fSJoe Komlodi s->id);
18397d87775fSJoe Komlodi
18407d87775fSJoe Komlodi sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
18417d87775fSJoe Komlodi
18427d87775fSJoe Komlodi memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i3c_device_ops,
18437d87775fSJoe Komlodi s, name, ASPEED_I3C_DEVICE_NR_REGS << 2);
18444ba25376SJoe Komlodi
18454ba25376SJoe Komlodi fifo32_create(&s->cmd_queue, ASPEED_I3C_CMD_QUEUE_CAPACITY);
18464ba25376SJoe Komlodi fifo32_create(&s->resp_queue, ASPEED_I3C_RESP_QUEUE_CAPACITY);
18474ba25376SJoe Komlodi fifo32_create(&s->tx_queue, ASPEED_I3C_TX_QUEUE_CAPACITY);
18484ba25376SJoe Komlodi fifo32_create(&s->rx_queue, ASPEED_I3C_RX_QUEUE_CAPACITY);
184993ec6949SJoe Komlodi fifo32_create(&s->ibi_queue, ASPEED_I3C_IBI_QUEUE_CAPACITY);
185093ec6949SJoe Komlodi /* Arbitrarily large enough to not be an issue. */
185193ec6949SJoe Komlodi fifo8_create(&s->ibi_data.ibi_intermediate_queue,
185293ec6949SJoe Komlodi ASPEED_I3C_IBI_QUEUE_CAPACITY * 8);
18534ba25376SJoe Komlodi
18544ba25376SJoe Komlodi s->bus = i3c_init_bus(DEVICE(s), name);
185593ec6949SJoe Komlodi I3CBusClass *bc = I3C_BUS_GET_CLASS(s->bus);
185693ec6949SJoe Komlodi bc->ibi_handle = aspeed_i3c_device_ibi_handle;
185793ec6949SJoe Komlodi bc->ibi_recv = aspeed_i3c_device_ibi_recv;
185893ec6949SJoe Komlodi bc->ibi_finish = aspeed_i3c_device_ibi_finish;
18597d87775fSJoe Komlodi }
18607d87775fSJoe Komlodi
aspeed_i3c_read(void * opaque,hwaddr addr,unsigned int size)18617d87775fSJoe Komlodi static uint64_t aspeed_i3c_read(void *opaque, hwaddr addr, unsigned int size)
18627d87775fSJoe Komlodi {
18637d87775fSJoe Komlodi AspeedI3CState *s = ASPEED_I3C(opaque);
18647d87775fSJoe Komlodi uint64_t val = 0;
18657d87775fSJoe Komlodi
18667d87775fSJoe Komlodi val = s->regs[addr >> 2];
18677d87775fSJoe Komlodi
18687d87775fSJoe Komlodi trace_aspeed_i3c_read(addr, val);
18697d87775fSJoe Komlodi
18707d87775fSJoe Komlodi return val;
18717d87775fSJoe Komlodi }
18727d87775fSJoe Komlodi
aspeed_i3c_write(void * opaque,hwaddr addr,uint64_t data,unsigned int size)18737d87775fSJoe Komlodi static void aspeed_i3c_write(void *opaque,
18747d87775fSJoe Komlodi hwaddr addr,
18757d87775fSJoe Komlodi uint64_t data,
18767d87775fSJoe Komlodi unsigned int size)
18777d87775fSJoe Komlodi {
18787d87775fSJoe Komlodi AspeedI3CState *s = ASPEED_I3C(opaque);
18797d87775fSJoe Komlodi
18807d87775fSJoe Komlodi trace_aspeed_i3c_write(addr, data);
18817d87775fSJoe Komlodi
18827d87775fSJoe Komlodi addr >>= 2;
18837d87775fSJoe Komlodi
1884a9d3f922SJoe Komlodi data &= ~ast2600_i3c_controller_ro[addr];
18857d87775fSJoe Komlodi /* I3C controller register */
18867d87775fSJoe Komlodi switch (addr) {
18877d87775fSJoe Komlodi case R_I3C1_REG1:
18887d87775fSJoe Komlodi case R_I3C2_REG1:
18897d87775fSJoe Komlodi case R_I3C3_REG1:
18907d87775fSJoe Komlodi case R_I3C4_REG1:
18917d87775fSJoe Komlodi case R_I3C5_REG1:
18927d87775fSJoe Komlodi case R_I3C6_REG1:
18937d87775fSJoe Komlodi if (data & R_I3C1_REG1_I2C_MODE_MASK) {
18947d87775fSJoe Komlodi qemu_log_mask(LOG_UNIMP,
18957d87775fSJoe Komlodi "%s: Unsupported I2C mode [0x%08" HWADDR_PRIx
18967d87775fSJoe Komlodi "]=%08" PRIx64 "\n",
18977d87775fSJoe Komlodi __func__, addr << 2, data);
18987d87775fSJoe Komlodi break;
18997d87775fSJoe Komlodi }
19007d87775fSJoe Komlodi if (data & R_I3C1_REG1_SA_EN_MASK) {
19017d87775fSJoe Komlodi qemu_log_mask(LOG_UNIMP,
19027d87775fSJoe Komlodi "%s: Unsupported slave mode [%08" HWADDR_PRIx
19037d87775fSJoe Komlodi "]=0x%08" PRIx64 "\n",
19047d87775fSJoe Komlodi __func__, addr << 2, data);
19057d87775fSJoe Komlodi break;
19067d87775fSJoe Komlodi }
19077d87775fSJoe Komlodi s->regs[addr] = data;
19087d87775fSJoe Komlodi break;
19097d87775fSJoe Komlodi default:
19107d87775fSJoe Komlodi s->regs[addr] = data;
19117d87775fSJoe Komlodi break;
19127d87775fSJoe Komlodi }
19137d87775fSJoe Komlodi }
19147d87775fSJoe Komlodi
19157d87775fSJoe Komlodi static const MemoryRegionOps aspeed_i3c_ops = {
19167d87775fSJoe Komlodi .read = aspeed_i3c_read,
19177d87775fSJoe Komlodi .write = aspeed_i3c_write,
19187d87775fSJoe Komlodi .endianness = DEVICE_LITTLE_ENDIAN,
19197d87775fSJoe Komlodi .valid = {
19207d87775fSJoe Komlodi .min_access_size = 1,
19217d87775fSJoe Komlodi .max_access_size = 4,
19227d87775fSJoe Komlodi }
19237d87775fSJoe Komlodi };
19247d87775fSJoe Komlodi
aspeed_i3c_reset(DeviceState * dev)19257d87775fSJoe Komlodi static void aspeed_i3c_reset(DeviceState *dev)
19267d87775fSJoe Komlodi {
19277d87775fSJoe Komlodi AspeedI3CState *s = ASPEED_I3C(dev);
19287d87775fSJoe Komlodi memset(s->regs, 0, sizeof(s->regs));
19297d87775fSJoe Komlodi }
19307d87775fSJoe Komlodi
aspeed_i3c_instance_init(Object * obj)19317d87775fSJoe Komlodi static void aspeed_i3c_instance_init(Object *obj)
19327d87775fSJoe Komlodi {
19337d87775fSJoe Komlodi AspeedI3CState *s = ASPEED_I3C(obj);
19347d87775fSJoe Komlodi int i;
19357d87775fSJoe Komlodi
19367d87775fSJoe Komlodi for (i = 0; i < ASPEED_I3C_NR_DEVICES; ++i) {
19377d87775fSJoe Komlodi object_initialize_child(obj, "device[*]", &s->devices[i],
19387d87775fSJoe Komlodi TYPE_ASPEED_I3C_DEVICE);
19397d87775fSJoe Komlodi }
19407d87775fSJoe Komlodi }
19417d87775fSJoe Komlodi
aspeed_i3c_realize(DeviceState * dev,Error ** errp)19427d87775fSJoe Komlodi static void aspeed_i3c_realize(DeviceState *dev, Error **errp)
19437d87775fSJoe Komlodi {
19447d87775fSJoe Komlodi int i;
19457d87775fSJoe Komlodi AspeedI3CState *s = ASPEED_I3C(dev);
19467d87775fSJoe Komlodi SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
19477d87775fSJoe Komlodi
19487d87775fSJoe Komlodi memory_region_init(&s->iomem_container, OBJECT(s),
19497d87775fSJoe Komlodi TYPE_ASPEED_I3C ".container", 0x8000);
19507d87775fSJoe Komlodi
19517d87775fSJoe Komlodi sysbus_init_mmio(sbd, &s->iomem_container);
19527d87775fSJoe Komlodi
19537d87775fSJoe Komlodi memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i3c_ops, s,
19547d87775fSJoe Komlodi TYPE_ASPEED_I3C ".regs", ASPEED_I3C_NR_REGS << 2);
19557d87775fSJoe Komlodi
19567d87775fSJoe Komlodi memory_region_add_subregion(&s->iomem_container, 0x0, &s->iomem);
19577d87775fSJoe Komlodi
19587d87775fSJoe Komlodi for (i = 0; i < ASPEED_I3C_NR_DEVICES; ++i) {
19597d87775fSJoe Komlodi Object *i3c_dev = OBJECT(&s->devices[i]);
19607d87775fSJoe Komlodi
19617d87775fSJoe Komlodi if (!object_property_set_uint(i3c_dev, "device-id", i, errp)) {
19627d87775fSJoe Komlodi return;
19637d87775fSJoe Komlodi }
19647d87775fSJoe Komlodi
19657d87775fSJoe Komlodi if (!sysbus_realize(SYS_BUS_DEVICE(i3c_dev), errp)) {
19667d87775fSJoe Komlodi return;
19677d87775fSJoe Komlodi }
19687d87775fSJoe Komlodi
19697d87775fSJoe Komlodi /*
19707d87775fSJoe Komlodi * Register Address of I3CX Device =
19717d87775fSJoe Komlodi * (Base Address of Global Register) + (Offset of I3CX) + Offset
19727d87775fSJoe Komlodi * X = 0, 1, 2, 3, 4, 5
19737d87775fSJoe Komlodi * Offset of I3C0 = 0x2000
19747d87775fSJoe Komlodi * Offset of I3C1 = 0x3000
19757d87775fSJoe Komlodi * Offset of I3C2 = 0x4000
19767d87775fSJoe Komlodi * Offset of I3C3 = 0x5000
19777d87775fSJoe Komlodi * Offset of I3C4 = 0x6000
19787d87775fSJoe Komlodi * Offset of I3C5 = 0x7000
19797d87775fSJoe Komlodi */
19807d87775fSJoe Komlodi memory_region_add_subregion(&s->iomem_container,
19817d87775fSJoe Komlodi 0x2000 + i * 0x1000, &s->devices[i].mr);
19827d87775fSJoe Komlodi }
19837d87775fSJoe Komlodi
19847d87775fSJoe Komlodi }
19857d87775fSJoe Komlodi
19867d87775fSJoe Komlodi static Property aspeed_i3c_device_properties[] = {
19877d87775fSJoe Komlodi DEFINE_PROP_UINT8("device-id", AspeedI3CDevice, id, 0),
19887d87775fSJoe Komlodi DEFINE_PROP_END_OF_LIST(),
19897d87775fSJoe Komlodi };
19907d87775fSJoe Komlodi
aspeed_i3c_device_class_init(ObjectClass * klass,void * data)19917d87775fSJoe Komlodi static void aspeed_i3c_device_class_init(ObjectClass *klass, void *data)
19927d87775fSJoe Komlodi {
19937d87775fSJoe Komlodi DeviceClass *dc = DEVICE_CLASS(klass);
19947d87775fSJoe Komlodi
19957d87775fSJoe Komlodi dc->desc = "Aspeed I3C Device";
19967d87775fSJoe Komlodi dc->realize = aspeed_i3c_device_realize;
19977d87775fSJoe Komlodi device_class_set_legacy_reset(dc, aspeed_i3c_device_reset);
19987d87775fSJoe Komlodi device_class_set_props(dc, aspeed_i3c_device_properties);
19997d87775fSJoe Komlodi }
20007d87775fSJoe Komlodi
20017d87775fSJoe Komlodi static const TypeInfo aspeed_i3c_device_info = {
20027d87775fSJoe Komlodi .name = TYPE_ASPEED_I3C_DEVICE,
20037d87775fSJoe Komlodi .parent = TYPE_SYS_BUS_DEVICE,
20047d87775fSJoe Komlodi .instance_size = sizeof(AspeedI3CDevice),
20057d87775fSJoe Komlodi .class_init = aspeed_i3c_device_class_init,
20067d87775fSJoe Komlodi };
20077d87775fSJoe Komlodi
20087d87775fSJoe Komlodi static const VMStateDescription vmstate_aspeed_i3c = {
20097d87775fSJoe Komlodi .name = TYPE_ASPEED_I3C,
20107d87775fSJoe Komlodi .version_id = 1,
20117d87775fSJoe Komlodi .minimum_version_id = 1,
20127d87775fSJoe Komlodi .fields = (const VMStateField[]) {
20137d87775fSJoe Komlodi VMSTATE_UINT32_ARRAY(regs, AspeedI3CState, ASPEED_I3C_NR_REGS),
20147d87775fSJoe Komlodi VMSTATE_STRUCT_ARRAY(devices, AspeedI3CState, ASPEED_I3C_NR_DEVICES, 1,
20157d87775fSJoe Komlodi aspeed_i3c_device_vmstate, AspeedI3CDevice),
20167d87775fSJoe Komlodi VMSTATE_END_OF_LIST(),
20177d87775fSJoe Komlodi }
20187d87775fSJoe Komlodi };
20197d87775fSJoe Komlodi
aspeed_i3c_class_init(ObjectClass * klass,void * data)20207d87775fSJoe Komlodi static void aspeed_i3c_class_init(ObjectClass *klass, void *data)
20217d87775fSJoe Komlodi {
20227d87775fSJoe Komlodi DeviceClass *dc = DEVICE_CLASS(klass);
20237d87775fSJoe Komlodi
20247d87775fSJoe Komlodi dc->realize = aspeed_i3c_realize;
20257d87775fSJoe Komlodi device_class_set_legacy_reset(dc, aspeed_i3c_reset);
20267d87775fSJoe Komlodi dc->desc = "Aspeed I3C Controller";
20277d87775fSJoe Komlodi dc->vmsd = &vmstate_aspeed_i3c;
20287d87775fSJoe Komlodi }
20297d87775fSJoe Komlodi
20307d87775fSJoe Komlodi static const TypeInfo aspeed_i3c_info = {
20317d87775fSJoe Komlodi .name = TYPE_ASPEED_I3C,
20327d87775fSJoe Komlodi .parent = TYPE_SYS_BUS_DEVICE,
20337d87775fSJoe Komlodi .instance_init = aspeed_i3c_instance_init,
20347d87775fSJoe Komlodi .instance_size = sizeof(AspeedI3CState),
20357d87775fSJoe Komlodi .class_init = aspeed_i3c_class_init,
20367d87775fSJoe Komlodi };
20377d87775fSJoe Komlodi
aspeed_i3c_register_types(void)20387d87775fSJoe Komlodi static void aspeed_i3c_register_types(void)
20397d87775fSJoe Komlodi {
20407d87775fSJoe Komlodi type_register_static(&aspeed_i3c_device_info);
20417d87775fSJoe Komlodi type_register_static(&aspeed_i3c_info);
20427d87775fSJoe Komlodi }
20437d87775fSJoe Komlodi
20447d87775fSJoe Komlodi type_init(aspeed_i3c_register_types);
2045