xref: /openbmc/qemu/include/hw/i3c/aspeed_i3c.h (revision b529230c)
1 /*
2  * ASPEED I3C Controller
3  *
4  * Copyright (C) 2021 ASPEED Technology Inc.
5  * Copyright (C) 2023 Google, LLC
6  *
7  * This code is licensed under the GPL version 2 or later.  See
8  * the COPYING file in the top-level directory.
9  */
10 
11 #ifndef ASPEED_I3C_H
12 #define ASPEED_I3C_H
13 
14 #include "qemu/fifo32.h"
15 #include "hw/i3c/i3c.h"
16 #include "hw/sysbus.h"
17 
18 #define TYPE_ASPEED_I3C "aspeed.i3c"
19 #define TYPE_ASPEED_I3C_DEVICE "aspeed.i3c.device"
20 OBJECT_DECLARE_TYPE(AspeedI3CState, AspeedI3CClass, ASPEED_I3C)
21 
22 #define ASPEED_I3C_NR_REGS (0x70 >> 2)
23 #define ASPEED_I3C_DEVICE_NR_REGS (0x300 >> 2)
24 #define ASPEED_I3C_NR_DEVICES 6
25 
26 #define ASPEED_I3C_CMD_QUEUE_CAPACITY  0x10
27 #define ASPEED_I3C_RESP_QUEUE_CAPACITY 0x10
28 #define ASPEED_I3C_TX_QUEUE_CAPACITY   0x40
29 #define ASPEED_I3C_RX_QUEUE_CAPACITY   0x40
30 #define ASPEED_I3C_IBI_QUEUE_CAPACITY  0x10
31 
32 /* From datasheet. */
33 #define ASPEED_I3C_CMD_ATTR_TRANSFER_CMD 0
34 #define ASPEED_I3C_CMD_ATTR_TRANSFER_ARG 1
35 #define ASPEED_I3C_CMD_ATTR_SHORT_DATA_ARG 2
36 #define ASPEED_I3C_CMD_ATTR_ADDR_ASSIGN_CMD 3
37 
38 /* Enum values from datasheet. */
39 typedef enum AspeedI3CRespQueueErr {
40     ASPEED_I3C_RESP_QUEUE_ERR_NONE = 0,
41     ASPEED_I3C_RESP_QUEUE_ERR_CRC = 1,
42     ASPEED_I3C_RESP_QUEUE_ERR_PARITY = 2,
43     ASPEED_I3C_RESP_QUEUE_ERR_FRAME = 3,
44     ASPEED_I3C_RESP_QUEUE_ERR_BROADCAST_NACK = 4,
45     ASPEED_I3C_RESP_QUEUE_ERR_DAA_NACK = 5,
46     ASPEED_I3C_RESP_QUEUE_ERR_OVERFLOW = 6,
47     ASPEED_I3C_RESP_QUEUE_ERR_ABORTED = 8,
48     ASPEED_I3C_RESP_QUEUE_ERR_I2C_NACK = 9,
49 } AspeedI3CRespQueueErr;
50 
51 typedef enum AspeedI3CTransferState {
52     ASPEED_I3C_TRANSFER_STATE_IDLE = 0x00,
53     ASPEED_I3C_TRANSFER_STATE_START = 0x01,
54     ASPEED_I3C_TRANSFER_STATE_RESTART = 0x02,
55     ASPEED_I3C_TRANSFER_STATE_STOP = 0x03,
56     ASPEED_I3C_TRANSFER_STATE_START_HOLD = 0x04,
57     ASPEED_I3C_TRANSFER_STATE_BROADCAST_W = 0x05,
58     ASPEED_I3C_TRANSFER_STATE_BROADCAST_R = 0x06,
59     ASPEED_I3C_TRANSFER_STATE_DAA = 0x07,
60     ASPEED_I3C_TRANSFER_STATE_DAA_GEN = 0x08,
61     ASPEED_I3C_TRANSFER_STATE_CCC_BYTE = 0x0b,
62     ASPEED_I3C_TRANSFER_STATE_HDR_CMD = 0x0c,
63     ASPEED_I3C_TRANSFER_STATE_WRITE = 0x0d,
64     ASPEED_I3C_TRANSFER_STATE_READ = 0x0e,
65     ASPEED_I3C_TRANSFER_STATE_IBI_READ = 0x0f,
66     ASPEED_I3C_TRANSFER_STATE_IBI_DIS = 0x10,
67     ASPEED_I3C_TRANSFER_STATE_HDR_DDR_CRC = 0x11,
68     ASPEED_I3C_TRANSFER_STATE_CLK_STRETCH = 0x12,
69     ASPEED_I3C_TRANSFER_STATE_HALT = 0x13,
70 } AspeedI3CTransferState;
71 
72 typedef enum AspeedI3CTransferStatus {
73     ASPEED_I3C_TRANSFER_STATUS_IDLE = 0x00,
74     ASPEED_I3C_TRANSFER_STATUS_BROACAST_CCC = 0x01,
75     ASPEED_I3C_TRANSFER_STATUS_DIRECT_CCC_W = 0x02,
76     ASPEED_I3C_TRANSFER_STATUS_DIRECT_CCC_R = 0x03,
77     ASPEED_I3C_TRANSFER_STATUS_ENTDAA = 0x04,
78     ASPEED_I3C_TRANSFER_STATUS_SETDASA = 0x05,
79     ASPEED_I3C_TRANSFER_STATUS_I3C_SDR_W = 0x06,
80     ASPEED_I3C_TRANSFER_STATUS_I3C_SDR_R = 0x07,
81     ASPEED_I3C_TRANSFER_STATUS_I2C_SDR_W = 0x08,
82     ASPEED_I3C_TRANSFER_STATUS_I2C_SDR_R = 0x09,
83     ASPEED_I3C_TRANSFER_STATUS_HDR_TS_W = 0x0a,
84     ASPEED_I3C_TRANSFER_STATUS_HDR_TS_R = 0x0b,
85     ASPEED_I3C_TRANSFER_STATUS_HDR_DDR_W = 0x0c,
86     ASPEED_I3C_TRANSFER_STATUS_HDR_DDR_R = 0x0d,
87     ASPEED_I3C_TRANSFER_STATUS_IBI = 0x0e,
88     ASPEED_I3C_TRANSFER_STATUS_HALT = 0x0f,
89 } AspeedI3CTransferStatus;
90 
91 /*
92  * Transfer commands and arguments are 32-bit wide values that the user passes
93  * into the command queue. We interpret each 32-bit word based on the cmd_attr
94  * field.
95  */
96 typedef struct AspeedI3CTransferCmd {
97     uint8_t cmd_attr:3;
98     uint8_t tid:4; /* Transaction ID */
99     uint16_t cmd:8;
100     uint8_t cp:1; /* Command present */
101     uint8_t dev_index:5;
102     uint8_t speed:3;
103     uint8_t resv0:1;
104     uint8_t dbp:1; /* Defining byte present */
105     uint8_t roc:1; /* Response on completion */
106     uint8_t sdap:1; /* Short data argument present */
107     uint8_t rnw:1; /* Read not write */
108     uint8_t resv1:1;
109     uint8_t toc:1; /* Termination (I3C STOP) on completion */
110     uint8_t pec:1; /* Parity error check enabled */
111 } AspeedI3CTransferCmd;
112 
113 typedef struct AspeedI3CTransferArg {
114     uint8_t cmd_attr:3;
115     uint8_t resv:5;
116     uint8_t db; /* Defining byte */
117     uint16_t data_len;
118 } AspeedI3CTransferArg;
119 
120 typedef struct AspeedI3CShortArg {
121     uint8_t cmd_attr:3;
122     uint8_t byte_strb:3;
123     uint8_t resv:2;
124     uint8_t byte0;
125     uint8_t byte1;
126     uint8_t byte2;
127 } AspeedI3CShortArg;
128 
129 typedef struct AspeedI3CAddrAssignCmd {
130     uint8_t cmd_attr:3;
131     uint8_t tid:4; /* Transaction ID */
132     uint16_t cmd:8;
133     uint8_t resv0:1;
134     uint8_t dev_index:5;
135     uint16_t dev_count:5;
136     uint8_t roc:1; /* Response on completion */
137     uint8_t resv1:3;
138     uint8_t toc:1; /* Termination (I3C STOP) on completion */
139     uint8_t resv2:1;
140 } AspeedI3CAddrAssignCmd;
141 
142 typedef union AspeedI3CCmdQueueData {
143     uint32_t word;
144     AspeedI3CTransferCmd transfer_cmd;
145     AspeedI3CTransferArg transfer_arg;
146     AspeedI3CShortArg short_arg;
147     AspeedI3CAddrAssignCmd addr_assign_cmd;
148 } AspeedI3CCmdQueueData;
149 
150 /*
151  * When we receive an IBI with data, we need to store it temporarily until
152  * the target is finished sending data. Then we can set the IBI queue status
153  * appropriately.
154  */
155 typedef struct AspeedI3CDeviceIBIData {
156     /* Do we notify the user that an IBI was NACKed? */
157     bool notify_ibi_nack;
158     /* Intermediate storage of IBI_QUEUE_STATUS. */
159     uint32_t ibi_queue_status;
160     /* Temporary buffer to store IBI data from the target. */
161     Fifo8 ibi_intermediate_queue;
162     /* The address we should send a CCC_DISEC to. */
163     uint8_t disec_addr;
164     /* The byte we should send along with the CCC_DISEC. */
165     uint8_t disec_byte;
166     /* Should we send a direct DISEC CCC? (As opposed to global). */
167     bool send_direct_disec;
168     /* Was this IBI NACKed? */
169     bool ibi_nacked;
170 } AspeedI3CDeviceIBIData;
171 
172 OBJECT_DECLARE_SIMPLE_TYPE(AspeedI3CDevice, ASPEED_I3C_DEVICE)
173 typedef struct AspeedI3CDevice {
174     /* <private> */
175     SysBusDevice parent;
176 
177     /* <public> */
178     MemoryRegion mr;
179     qemu_irq irq;
180     I3CBus *bus;
181 
182     Fifo32 cmd_queue;
183     Fifo32 resp_queue;
184     Fifo32 tx_queue;
185     Fifo32 rx_queue;
186     Fifo32 ibi_queue;
187 
188     /* Temporary storage for IBI data. */
189     AspeedI3CDeviceIBIData ibi_data;
190 
191     uint8_t id;
192     uint32_t regs[ASPEED_I3C_DEVICE_NR_REGS];
193 } AspeedI3CDevice;
194 
195 typedef struct AspeedI3CState {
196     /* <private> */
197     SysBusDevice parent;
198 
199     /* <public> */
200     MemoryRegion iomem;
201     MemoryRegion iomem_container;
202     qemu_irq irq;
203 
204     uint32_t regs[ASPEED_I3C_NR_REGS];
205     AspeedI3CDevice devices[ASPEED_I3C_NR_DEVICES];
206 } AspeedI3CState;
207 #endif /* ASPEED_I3C_H */
208