]>
Commit | Line | Data |
---|---|---|
16020011 CLG |
1 | /* |
2 | * ARM Aspeed I2C controller | |
3 | * | |
4 | * Copyright (C) 2016 IBM Corp. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version 2 | |
9 | * of the License, or (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
18 | * | |
19 | */ | |
20 | ||
21 | #include "qemu/osdep.h" | |
22 | #include "hw/sysbus.h" | |
d6454270 | 23 | #include "migration/vmstate.h" |
b03ec4ff | 24 | #include "qemu/cutils.h" |
16020011 | 25 | #include "qemu/log.h" |
0b8fa32f | 26 | #include "qemu/module.h" |
545d6bef CLG |
27 | #include "qemu/error-report.h" |
28 | #include "qapi/error.h" | |
16020011 | 29 | #include "hw/i2c/aspeed_i2c.h" |
64552b6b | 30 | #include "hw/irq.h" |
545d6bef | 31 | #include "hw/qdev-properties.h" |
3be3d6cc | 32 | #include "hw/registerfields.h" |
66cc84a1 | 33 | #include "trace.h" |
16020011 | 34 | |
33e30f11 CLG |
35 | /* Enable SLAVE_ADDR_RX_MATCH always */ |
36 | #define R_I2CD_INTR_STS_ALWAYS_ENABLE R_I2CD_INTR_STS_SLAVE_ADDR_RX_MATCH_MASK | |
37 | ||
16020011 CLG |
38 | static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus) |
39 | { | |
51dd4923 | 40 | AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); |
ba2cccd6 JK |
41 | uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); |
42 | uint32_t intr_ctrl_reg = aspeed_i2c_bus_intr_ctrl_offset(bus); | |
33e30f11 CLG |
43 | uint32_t intr_ctrl_mask = bus->regs[intr_ctrl_reg] | |
44 | R_I2CD_INTR_STS_ALWAYS_ENABLE; | |
ba2cccd6 JK |
45 | bool raise_irq; |
46 | ||
b03ec4ff | 47 | if (trace_event_get_state_backends(TRACE_ASPEED_I2C_BUS_RAISE_INTERRUPT)) { |
33e30f11 | 48 | g_autofree char *buf = g_strdup_printf("%s%s%s%s%s%s%s", |
b03ec4ff KJ |
49 | aspeed_i2c_bus_pkt_mode_en(bus) && |
50 | ARRAY_FIELD_EX32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE) ? | |
51 | "pktdone|" : "", | |
52 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_NAK) ? | |
53 | "nak|" : "", | |
54 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_ACK) ? | |
55 | "ack|" : "", | |
56 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE) ? | |
57 | "done|" : "", | |
33e30f11 CLG |
58 | ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH) ? |
59 | "slave-match|" : "", | |
b03ec4ff | 60 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, NORMAL_STOP) ? |
6743af9b | 61 | "stop|" : "", |
b03ec4ff KJ |
62 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, ABNORMAL) ? |
63 | "abnormal" : ""); | |
64 | ||
65 | trace_aspeed_i2c_bus_raise_interrupt(bus->regs[reg_intr_sts], buf); | |
66 | } | |
67 | ||
33e30f11 | 68 | raise_irq = bus->regs[reg_intr_sts] & intr_ctrl_mask ; |
b03ec4ff | 69 | |
ba2cccd6 JK |
70 | /* In packet mode we don't mask off INTR_STS */ |
71 | if (!aspeed_i2c_bus_pkt_mode_en(bus)) { | |
33e30f11 | 72 | bus->regs[reg_intr_sts] &= intr_ctrl_mask; |
ba2cccd6 | 73 | } |
b03ec4ff | 74 | |
ba2cccd6 | 75 | if (raise_irq) { |
16020011 | 76 | bus->controller->intr_status |= 1 << bus->id; |
51dd4923 | 77 | qemu_irq_raise(aic->bus_get_irq(bus)); |
16020011 CLG |
78 | } |
79 | } | |
80 | ||
1c5d909f PD |
81 | static inline void aspeed_i2c_bus_raise_slave_interrupt(AspeedI2CBus *bus) |
82 | { | |
83 | AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); | |
84 | ||
85 | if (!bus->regs[R_I2CS_INTR_STS]) { | |
86 | return; | |
87 | } | |
88 | ||
89 | bus->controller->intr_status |= 1 << bus->id; | |
90 | qemu_irq_raise(aic->bus_get_irq(bus)); | |
91 | } | |
92 | ||
ba2cccd6 JK |
93 | static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, hwaddr offset, |
94 | unsigned size) | |
16020011 | 95 | { |
545d6bef | 96 | AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); |
2260fc6f | 97 | uint64_t value = bus->regs[offset / sizeof(*bus->regs)]; |
16020011 CLG |
98 | |
99 | switch (offset) { | |
3be3d6cc | 100 | case A_I2CD_FUN_CTRL: |
3be3d6cc | 101 | case A_I2CD_AC_TIMING1: |
3be3d6cc | 102 | case A_I2CD_AC_TIMING2: |
3be3d6cc | 103 | case A_I2CD_INTR_CTRL: |
3be3d6cc | 104 | case A_I2CD_INTR_STS: |
d72a712c | 105 | case A_I2CD_DEV_ADDR: |
3be3d6cc | 106 | case A_I2CD_POOL_CTRL: |
3be3d6cc | 107 | case A_I2CD_BYTE_BUF: |
2260fc6f | 108 | /* Value is already set, don't do anything. */ |
66cc84a1 | 109 | break; |
3be3d6cc | 110 | case A_I2CD_CMD: |
ba2cccd6 | 111 | value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus)); |
66cc84a1 | 112 | break; |
3be3d6cc | 113 | case A_I2CD_DMA_ADDR: |
545d6bef CLG |
114 | if (!aic->has_dma) { |
115 | qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); | |
2260fc6f | 116 | value = -1; |
545d6bef | 117 | } |
66cc84a1 | 118 | break; |
3be3d6cc | 119 | case A_I2CD_DMA_LEN: |
545d6bef CLG |
120 | if (!aic->has_dma) { |
121 | qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); | |
2260fc6f | 122 | value = -1; |
545d6bef | 123 | } |
66cc84a1 CLG |
124 | break; |
125 | ||
16020011 CLG |
126 | default: |
127 | qemu_log_mask(LOG_GUEST_ERROR, | |
128 | "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); | |
66cc84a1 CLG |
129 | value = -1; |
130 | break; | |
16020011 | 131 | } |
66cc84a1 CLG |
132 | |
133 | trace_aspeed_i2c_bus_read(bus->id, offset, size, value); | |
134 | return value; | |
16020011 CLG |
135 | } |
136 | ||
ba2cccd6 JK |
137 | static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset, |
138 | unsigned size) | |
139 | { | |
140 | uint64_t value = bus->regs[offset / sizeof(*bus->regs)]; | |
141 | ||
142 | switch (offset) { | |
143 | case A_I2CC_FUN_CTRL: | |
144 | case A_I2CC_AC_TIMING: | |
145 | case A_I2CC_POOL_CTRL: | |
146 | case A_I2CM_INTR_CTRL: | |
147 | case A_I2CM_INTR_STS: | |
148 | case A_I2CC_MS_TXRX_BYTE_BUF: | |
149 | case A_I2CM_DMA_LEN: | |
150 | case A_I2CM_DMA_TX_ADDR: | |
151 | case A_I2CM_DMA_RX_ADDR: | |
152 | case A_I2CM_DMA_LEN_STS: | |
153 | case A_I2CC_DMA_ADDR: | |
154 | case A_I2CC_DMA_LEN: | |
1c5d909f PD |
155 | |
156 | case A_I2CS_DEV_ADDR: | |
157 | case A_I2CS_DMA_RX_ADDR: | |
158 | case A_I2CS_DMA_LEN: | |
159 | case A_I2CS_CMD: | |
160 | case A_I2CS_INTR_CTRL: | |
161 | case A_I2CS_DMA_LEN_STS: | |
ba2cccd6 JK |
162 | /* Value is already set, don't do anything. */ |
163 | break; | |
1c5d909f PD |
164 | case A_I2CS_INTR_STS: |
165 | break; | |
ba2cccd6 JK |
166 | case A_I2CM_CMD: |
167 | value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus)); | |
168 | break; | |
169 | default: | |
170 | qemu_log_mask(LOG_GUEST_ERROR, | |
171 | "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); | |
172 | value = -1; | |
173 | break; | |
174 | } | |
175 | ||
176 | trace_aspeed_i2c_bus_read(bus->id, offset, size, value); | |
177 | return value; | |
178 | } | |
179 | ||
180 | static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset, | |
181 | unsigned size) | |
182 | { | |
183 | AspeedI2CBus *bus = opaque; | |
184 | if (aspeed_i2c_is_new_mode(bus->controller)) { | |
185 | return aspeed_i2c_bus_new_read(bus, offset, size); | |
186 | } | |
187 | return aspeed_i2c_bus_old_read(bus, offset, size); | |
188 | } | |
189 | ||
4960f084 CLG |
190 | static void aspeed_i2c_set_state(AspeedI2CBus *bus, uint8_t state) |
191 | { | |
ba2cccd6 JK |
192 | if (aspeed_i2c_is_new_mode(bus->controller)) { |
193 | SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, TX_STATE, | |
194 | state); | |
195 | } else { | |
196 | SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CD_CMD, TX_STATE, state); | |
197 | } | |
4960f084 CLG |
198 | } |
199 | ||
200 | static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus) | |
201 | { | |
ba2cccd6 JK |
202 | if (aspeed_i2c_is_new_mode(bus->controller)) { |
203 | return SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, | |
204 | TX_STATE); | |
205 | } | |
206 | return SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, TX_STATE); | |
4960f084 CLG |
207 | } |
208 | ||
545d6bef CLG |
209 | static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data) |
210 | { | |
211 | MemTxResult result; | |
212 | AspeedI2CState *s = bus->controller; | |
ba2cccd6 JK |
213 | uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus); |
214 | uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); | |
545d6bef | 215 | |
ba2cccd6 | 216 | result = address_space_read(&s->dram_as, bus->regs[reg_dma_addr], |
545d6bef CLG |
217 | MEMTXATTRS_UNSPECIFIED, data, 1); |
218 | if (result != MEMTX_OK) { | |
219 | qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM read failed @%08x\n", | |
ba2cccd6 | 220 | __func__, bus->regs[reg_dma_addr]); |
545d6bef CLG |
221 | return -1; |
222 | } | |
223 | ||
ba2cccd6 JK |
224 | bus->regs[reg_dma_addr]++; |
225 | bus->regs[reg_dma_len]--; | |
545d6bef CLG |
226 | return 0; |
227 | } | |
228 | ||
6054fc73 CLG |
229 | static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start) |
230 | { | |
231 | AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); | |
232 | int ret = -1; | |
233 | int i; | |
ba2cccd6 JK |
234 | uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); |
235 | uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); | |
236 | uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); | |
237 | uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); | |
238 | int pool_tx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, | |
239 | TX_COUNT); | |
240 | ||
241 | if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { | |
3be3d6cc | 242 | for (i = pool_start; i < pool_tx_count; i++) { |
6054fc73 CLG |
243 | uint8_t *pool_base = aic->bus_pool_base(bus); |
244 | ||
3be3d6cc | 245 | trace_aspeed_i2c_bus_send("BUF", i + 1, pool_tx_count, |
66cc84a1 | 246 | pool_base[i]); |
6054fc73 CLG |
247 | ret = i2c_send(bus->bus, pool_base[i]); |
248 | if (ret) { | |
249 | break; | |
250 | } | |
251 | } | |
ba2cccd6 JK |
252 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, TX_BUFF_EN, 0); |
253 | } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { | |
254 | /* In new mode, clear how many bytes we TXed */ | |
255 | if (aspeed_i2c_is_new_mode(bus->controller)) { | |
256 | ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, TX_LEN, 0); | |
257 | } | |
258 | while (bus->regs[reg_dma_len]) { | |
545d6bef CLG |
259 | uint8_t data; |
260 | aspeed_i2c_dma_read(bus, &data); | |
ba2cccd6 JK |
261 | trace_aspeed_i2c_bus_send("DMA", bus->regs[reg_dma_len], |
262 | bus->regs[reg_dma_len], data); | |
545d6bef CLG |
263 | ret = i2c_send(bus->bus, data); |
264 | if (ret) { | |
265 | break; | |
266 | } | |
ba2cccd6 JK |
267 | /* In new mode, keep track of how many bytes we TXed */ |
268 | if (aspeed_i2c_is_new_mode(bus->controller)) { | |
269 | ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, TX_LEN, | |
270 | ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN_STS, | |
271 | TX_LEN) + 1); | |
272 | } | |
545d6bef | 273 | } |
ba2cccd6 | 274 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, TX_DMA_EN, 0); |
6054fc73 | 275 | } else { |
2260fc6f | 276 | trace_aspeed_i2c_bus_send("BYTE", pool_start, 1, |
ba2cccd6 JK |
277 | bus->regs[reg_byte_buf]); |
278 | ret = i2c_send(bus->bus, bus->regs[reg_byte_buf]); | |
6054fc73 CLG |
279 | } |
280 | ||
281 | return ret; | |
282 | } | |
283 | ||
284 | static void aspeed_i2c_bus_recv(AspeedI2CBus *bus) | |
7bd9c60d | 285 | { |
6054fc73 CLG |
286 | AspeedI2CState *s = bus->controller; |
287 | AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); | |
288 | uint8_t data; | |
289 | int i; | |
ba2cccd6 JK |
290 | uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); |
291 | uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); | |
292 | uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); | |
293 | uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); | |
294 | uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus); | |
295 | int pool_rx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, | |
296 | RX_COUNT); | |
297 | ||
298 | if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) { | |
6054fc73 | 299 | uint8_t *pool_base = aic->bus_pool_base(bus); |
7bd9c60d | 300 | |
3be3d6cc | 301 | for (i = 0; i < pool_rx_count; i++) { |
6054fc73 | 302 | pool_base[i] = i2c_recv(bus->bus); |
3be3d6cc | 303 | trace_aspeed_i2c_bus_recv("BUF", i + 1, pool_rx_count, |
66cc84a1 | 304 | pool_base[i]); |
6054fc73 CLG |
305 | } |
306 | ||
307 | /* Update RX count */ | |
ba2cccd6 JK |
308 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_pool_ctrl, RX_COUNT, i & 0xff); |
309 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_BUFF_EN, 0); | |
310 | } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { | |
545d6bef | 311 | uint8_t data; |
ba2cccd6 JK |
312 | /* In new mode, clear how many bytes we RXed */ |
313 | if (aspeed_i2c_is_new_mode(bus->controller)) { | |
314 | ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 0); | |
315 | } | |
545d6bef | 316 | |
ba2cccd6 | 317 | while (bus->regs[reg_dma_len]) { |
545d6bef CLG |
318 | MemTxResult result; |
319 | ||
320 | data = i2c_recv(bus->bus); | |
ba2cccd6 JK |
321 | trace_aspeed_i2c_bus_recv("DMA", bus->regs[reg_dma_len], |
322 | bus->regs[reg_dma_len], data); | |
323 | result = address_space_write(&s->dram_as, bus->regs[reg_dma_addr], | |
545d6bef CLG |
324 | MEMTXATTRS_UNSPECIFIED, &data, 1); |
325 | if (result != MEMTX_OK) { | |
326 | qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n", | |
ba2cccd6 | 327 | __func__, bus->regs[reg_dma_addr]); |
545d6bef CLG |
328 | return; |
329 | } | |
ba2cccd6 JK |
330 | bus->regs[reg_dma_addr]++; |
331 | bus->regs[reg_dma_len]--; | |
332 | /* In new mode, keep track of how many bytes we RXed */ | |
333 | if (aspeed_i2c_is_new_mode(bus->controller)) { | |
334 | ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, | |
335 | ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN_STS, | |
336 | RX_LEN) + 1); | |
337 | } | |
545d6bef | 338 | } |
ba2cccd6 | 339 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_DMA_EN, 0); |
6054fc73 CLG |
340 | } else { |
341 | data = i2c_recv(bus->bus); | |
ba2cccd6 JK |
342 | trace_aspeed_i2c_bus_recv("BYTE", 1, 1, bus->regs[reg_byte_buf]); |
343 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data); | |
6054fc73 CLG |
344 | } |
345 | } | |
346 | ||
347 | static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus) | |
348 | { | |
ba2cccd6 JK |
349 | uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); |
350 | uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); | |
351 | ||
7bd9c60d | 352 | aspeed_i2c_set_state(bus, I2CD_MRXD); |
6054fc73 | 353 | aspeed_i2c_bus_recv(bus); |
ba2cccd6 JK |
354 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); |
355 | if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST)) { | |
7bd9c60d GR |
356 | i2c_nack(bus->bus); |
357 | } | |
ba2cccd6 JK |
358 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_RX_CMD, 0); |
359 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_S_RX_CMD_LAST, 0); | |
7bd9c60d GR |
360 | aspeed_i2c_set_state(bus, I2CD_MACTIVE); |
361 | } | |
362 | ||
6054fc73 CLG |
363 | static uint8_t aspeed_i2c_get_addr(AspeedI2CBus *bus) |
364 | { | |
365 | AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); | |
ba2cccd6 JK |
366 | uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); |
367 | uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); | |
6054fc73 | 368 | |
ba2cccd6 JK |
369 | if (aspeed_i2c_bus_pkt_mode_en(bus)) { |
370 | return (ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, PKT_DEV_ADDR) << 1) | | |
371 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD); | |
372 | } | |
373 | if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { | |
6054fc73 CLG |
374 | uint8_t *pool_base = aic->bus_pool_base(bus); |
375 | ||
376 | return pool_base[0]; | |
ba2cccd6 | 377 | } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { |
545d6bef CLG |
378 | uint8_t data; |
379 | ||
380 | aspeed_i2c_dma_read(bus, &data); | |
381 | return data; | |
6054fc73 | 382 | } else { |
ba2cccd6 | 383 | return bus->regs[reg_byte_buf]; |
6054fc73 CLG |
384 | } |
385 | } | |
386 | ||
aab90b1c CLG |
387 | static bool aspeed_i2c_check_sram(AspeedI2CBus *bus) |
388 | { | |
389 | AspeedI2CState *s = bus->controller; | |
390 | AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); | |
ba2cccd6 JK |
391 | uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); |
392 | bool dma_en = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN) || | |
393 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN) || | |
394 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN) || | |
395 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN); | |
aab90b1c CLG |
396 | if (!aic->check_sram) { |
397 | return true; | |
398 | } | |
399 | ||
400 | /* | |
401 | * AST2500: SRAM must be enabled before using the Buffer Pool or | |
402 | * DMA mode. | |
403 | */ | |
3be3d6cc | 404 | if (!FIELD_EX32(s->ctrl_global, I2C_CTRL_GLOBAL, SRAM_EN) && dma_en) { |
aab90b1c CLG |
405 | qemu_log_mask(LOG_GUEST_ERROR, "%s: SRAM is not enabled\n", __func__); |
406 | return false; | |
407 | } | |
408 | ||
409 | return true; | |
410 | } | |
411 | ||
66cc84a1 CLG |
412 | static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus) |
413 | { | |
f821bac4 | 414 | g_autofree char *cmd_flags = NULL; |
66cc84a1 | 415 | uint32_t count; |
ba2cccd6 JK |
416 | uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); |
417 | uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); | |
418 | uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); | |
419 | uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); | |
420 | if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) { | |
421 | count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT); | |
422 | } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { | |
423 | count = bus->regs[reg_dma_len]; | |
66cc84a1 CLG |
424 | } else { /* BYTE mode */ |
425 | count = 1; | |
426 | } | |
427 | ||
428 | cmd_flags = g_strdup_printf("%s%s%s%s%s%s%s%s%s", | |
ba2cccd6 JK |
429 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_START_CMD) ? "start|" : "", |
430 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN) ? "rxdma|" : "", | |
431 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN) ? "txdma|" : "", | |
432 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN) ? "rxbuf|" : "", | |
433 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN) ? "txbuf|" : "", | |
434 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD) ? "tx|" : "", | |
435 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD) ? "rx|" : "", | |
436 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST) ? "last|" : "", | |
437 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_STOP_CMD) ? "stop|" : ""); | |
438 | ||
439 | trace_aspeed_i2c_bus_cmd(bus->regs[reg_cmd], cmd_flags, count, | |
440 | bus->regs[reg_intr_sts]); | |
66cc84a1 CLG |
441 | } |
442 | ||
4960f084 CLG |
443 | /* |
444 | * The state machine needs some refinement. It is only used to track | |
445 | * invalid STOP commands for the moment. | |
446 | */ | |
16020011 CLG |
447 | static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) |
448 | { | |
6054fc73 | 449 | uint8_t pool_start = 0; |
ba2cccd6 JK |
450 | uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); |
451 | uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); | |
452 | uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); | |
453 | uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); | |
16020011 | 454 | |
aab90b1c CLG |
455 | if (!aspeed_i2c_check_sram(bus)) { |
456 | return; | |
457 | } | |
458 | ||
66cc84a1 CLG |
459 | if (trace_event_get_state_backends(TRACE_ASPEED_I2C_BUS_CMD)) { |
460 | aspeed_i2c_bus_cmd_dump(bus); | |
461 | } | |
462 | ||
ba2cccd6 | 463 | if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_START_CMD)) { |
4960f084 CLG |
464 | uint8_t state = aspeed_i2c_get_state(bus) & I2CD_MACTIVE ? |
465 | I2CD_MSTARTR : I2CD_MSTART; | |
6054fc73 | 466 | uint8_t addr; |
4960f084 CLG |
467 | |
468 | aspeed_i2c_set_state(bus, state); | |
469 | ||
6054fc73 | 470 | addr = aspeed_i2c_get_addr(bus); |
6054fc73 CLG |
471 | if (i2c_start_transfer(bus->bus, extract32(addr, 1, 7), |
472 | extract32(addr, 0, 1))) { | |
ba2cccd6 JK |
473 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1); |
474 | if (aspeed_i2c_bus_pkt_mode_en(bus)) { | |
475 | ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); | |
476 | } | |
16020011 | 477 | } else { |
ba2cccd6 JK |
478 | /* START doesn't set TX_ACK in packet mode */ |
479 | if (!aspeed_i2c_bus_pkt_mode_en(bus)) { | |
480 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_ACK, 1); | |
481 | } | |
16020011 CLG |
482 | } |
483 | ||
ba2cccd6 | 484 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_START_CMD, 0); |
6054fc73 CLG |
485 | |
486 | /* | |
487 | * The START command is also a TX command, as the slave | |
488 | * address is sent on the bus. Drop the TX flag if nothing | |
489 | * else needs to be sent in this sequence. | |
490 | */ | |
ba2cccd6 JK |
491 | if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { |
492 | if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT) | |
493 | == 1) { | |
494 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); | |
6054fc73 CLG |
495 | } else { |
496 | /* | |
497 | * Increase the start index in the TX pool buffer to | |
498 | * skip the address byte. | |
499 | */ | |
500 | pool_start++; | |
501 | } | |
ba2cccd6 JK |
502 | } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { |
503 | if (bus->regs[reg_dma_len] == 0) { | |
504 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); | |
545d6bef | 505 | } |
6054fc73 | 506 | } else { |
ba2cccd6 | 507 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); |
6054fc73 | 508 | } |
ddabca75 CLG |
509 | |
510 | /* No slave found */ | |
511 | if (!i2c_bus_busy(bus->bus)) { | |
ba2cccd6 JK |
512 | if (aspeed_i2c_bus_pkt_mode_en(bus)) { |
513 | ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); | |
514 | ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE, 1); | |
515 | } | |
ddabca75 CLG |
516 | return; |
517 | } | |
4960f084 | 518 | aspeed_i2c_set_state(bus, I2CD_MACTIVE); |
ddabca75 CLG |
519 | } |
520 | ||
ba2cccd6 | 521 | if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD)) { |
4960f084 | 522 | aspeed_i2c_set_state(bus, I2CD_MTXD); |
6054fc73 | 523 | if (aspeed_i2c_bus_send(bus, pool_start)) { |
ba2cccd6 | 524 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1); |
16020011 CLG |
525 | i2c_end_transfer(bus->bus); |
526 | } else { | |
ba2cccd6 | 527 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_ACK, 1); |
16020011 | 528 | } |
ba2cccd6 | 529 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); |
4960f084 | 530 | aspeed_i2c_set_state(bus, I2CD_MACTIVE); |
ddabca75 | 531 | } |
16020011 | 532 | |
ba2cccd6 JK |
533 | if ((SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD) || |
534 | SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST)) && | |
535 | !SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE)) { | |
7bd9c60d | 536 | aspeed_i2c_handle_rx_cmd(bus); |
16020011 CLG |
537 | } |
538 | ||
ba2cccd6 | 539 | if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_STOP_CMD)) { |
4960f084 CLG |
540 | if (!(aspeed_i2c_get_state(bus) & I2CD_MACTIVE)) { |
541 | qemu_log_mask(LOG_GUEST_ERROR, "%s: abnormal stop\n", __func__); | |
ba2cccd6 JK |
542 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, ABNORMAL, 1); |
543 | if (aspeed_i2c_bus_pkt_mode_en(bus)) { | |
544 | ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); | |
545 | } | |
16020011 | 546 | } else { |
4960f084 | 547 | aspeed_i2c_set_state(bus, I2CD_MSTOP); |
16020011 | 548 | i2c_end_transfer(bus->bus); |
ba2cccd6 | 549 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, NORMAL_STOP, 1); |
16020011 | 550 | } |
ba2cccd6 | 551 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_STOP_CMD, 0); |
4960f084 | 552 | aspeed_i2c_set_state(bus, I2CD_IDLE); |
16020011 | 553 | } |
ba2cccd6 JK |
554 | |
555 | if (aspeed_i2c_bus_pkt_mode_en(bus)) { | |
556 | ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE, 1); | |
557 | } | |
16020011 CLG |
558 | } |
559 | ||
ba2cccd6 JK |
560 | static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset, |
561 | uint64_t value, unsigned size) | |
562 | { | |
563 | AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); | |
564 | bool handle_rx; | |
565 | bool w1t; | |
566 | ||
567 | trace_aspeed_i2c_bus_write(bus->id, offset, size, value); | |
568 | ||
569 | switch (offset) { | |
570 | case A_I2CC_FUN_CTRL: | |
1c5d909f | 571 | bus->regs[R_I2CC_FUN_CTRL] = value; |
ba2cccd6 JK |
572 | break; |
573 | case A_I2CC_AC_TIMING: | |
574 | bus->regs[R_I2CC_AC_TIMING] = value & 0x1ffff0ff; | |
575 | break; | |
576 | case A_I2CC_MS_TXRX_BYTE_BUF: | |
577 | SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, TX_BUF, | |
578 | value); | |
579 | break; | |
580 | case A_I2CC_POOL_CTRL: | |
581 | bus->regs[R_I2CC_POOL_CTRL] &= ~0xffffff; | |
582 | bus->regs[R_I2CC_POOL_CTRL] |= (value & 0xffffff); | |
583 | break; | |
584 | case A_I2CM_INTR_CTRL: | |
585 | bus->regs[R_I2CM_INTR_CTRL] = value & 0x0007f07f; | |
586 | break; | |
587 | case A_I2CM_INTR_STS: | |
588 | handle_rx = SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_INTR_STS, RX_DONE) | |
589 | && SHARED_FIELD_EX32(value, RX_DONE); | |
590 | ||
591 | /* In packet mode, clearing PKT_CMD_DONE clears other interrupts. */ | |
592 | if (aspeed_i2c_bus_pkt_mode_en(bus) && | |
593 | FIELD_EX32(value, I2CM_INTR_STS, PKT_CMD_DONE)) { | |
594 | bus->regs[R_I2CM_INTR_STS] &= 0xf0001000; | |
595 | if (!bus->regs[R_I2CM_INTR_STS]) { | |
596 | bus->controller->intr_status &= ~(1 << bus->id); | |
597 | qemu_irq_lower(aic->bus_get_irq(bus)); | |
598 | } | |
1c5d909f | 599 | aspeed_i2c_bus_raise_slave_interrupt(bus); |
ba2cccd6 JK |
600 | break; |
601 | } | |
602 | bus->regs[R_I2CM_INTR_STS] &= ~(value & 0xf007f07f); | |
603 | if (!bus->regs[R_I2CM_INTR_STS]) { | |
604 | bus->controller->intr_status &= ~(1 << bus->id); | |
605 | qemu_irq_lower(aic->bus_get_irq(bus)); | |
606 | } | |
607 | if (handle_rx && (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_CMD, | |
608 | M_RX_CMD) || | |
609 | SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_CMD, | |
610 | M_S_RX_CMD_LAST))) { | |
611 | aspeed_i2c_handle_rx_cmd(bus); | |
612 | aspeed_i2c_bus_raise_interrupt(bus); | |
613 | } | |
614 | break; | |
615 | case A_I2CM_CMD: | |
616 | if (!aspeed_i2c_bus_is_enabled(bus)) { | |
617 | break; | |
618 | } | |
619 | ||
620 | if (!aspeed_i2c_bus_is_master(bus)) { | |
0c0f1bee | 621 | qemu_log_mask(LOG_GUEST_ERROR, "%s: Master mode is not enabled\n", |
ba2cccd6 JK |
622 | __func__); |
623 | break; | |
624 | } | |
625 | ||
626 | if (!aic->has_dma && | |
627 | (SHARED_FIELD_EX32(value, RX_DMA_EN) || | |
628 | SHARED_FIELD_EX32(value, TX_DMA_EN))) { | |
629 | qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); | |
630 | break; | |
631 | } | |
632 | ||
633 | if (bus->regs[R_I2CM_INTR_STS] & 0xffff0000) { | |
634 | qemu_log_mask(LOG_UNIMP, "%s: Packet mode is not implemented\n", | |
635 | __func__); | |
636 | break; | |
637 | } | |
638 | ||
639 | value &= 0xff0ffbfb; | |
640 | if (ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, W1_CTRL)) { | |
641 | bus->regs[R_I2CM_CMD] |= value; | |
642 | } else { | |
643 | bus->regs[R_I2CM_CMD] = value; | |
644 | } | |
645 | ||
646 | aspeed_i2c_bus_handle_cmd(bus, value); | |
647 | aspeed_i2c_bus_raise_interrupt(bus); | |
648 | break; | |
649 | case A_I2CM_DMA_TX_ADDR: | |
650 | bus->regs[R_I2CM_DMA_TX_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR, | |
651 | ADDR); | |
652 | bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR, ADDR); | |
653 | bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, | |
654 | TX_BUF_LEN) + 1; | |
655 | break; | |
656 | case A_I2CM_DMA_RX_ADDR: | |
657 | bus->regs[R_I2CM_DMA_RX_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR, | |
658 | ADDR); | |
659 | bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR, ADDR); | |
660 | bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, | |
661 | RX_BUF_LEN) + 1; | |
662 | break; | |
663 | case A_I2CM_DMA_LEN: | |
b582b7a1 PD |
664 | w1t = FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN_W1T) || |
665 | FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN_W1T); | |
ba2cccd6 JK |
666 | /* If none of the w1t bits are set, just write to the reg as normal. */ |
667 | if (!w1t) { | |
668 | bus->regs[R_I2CM_DMA_LEN] = value; | |
669 | break; | |
670 | } | |
b582b7a1 | 671 | if (FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN_W1T)) { |
ba2cccd6 JK |
672 | ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN, |
673 | FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN)); | |
674 | } | |
b582b7a1 | 675 | if (FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN_W1T)) { |
ba2cccd6 JK |
676 | ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN, |
677 | FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN)); | |
678 | } | |
679 | break; | |
680 | case A_I2CM_DMA_LEN_STS: | |
681 | /* Writes clear to 0 */ | |
682 | bus->regs[R_I2CM_DMA_LEN_STS] = 0; | |
683 | break; | |
684 | case A_I2CC_DMA_ADDR: | |
685 | case A_I2CC_DMA_LEN: | |
686 | /* RO */ | |
687 | break; | |
ba2cccd6 | 688 | case A_I2CS_DEV_ADDR: |
1c5d909f PD |
689 | bus->regs[R_I2CS_DEV_ADDR] = value; |
690 | break; | |
691 | case A_I2CS_DMA_RX_ADDR: | |
692 | bus->regs[R_I2CS_DMA_RX_ADDR] = value; | |
693 | break; | |
694 | case A_I2CS_DMA_LEN: | |
695 | assert(FIELD_EX32(value, I2CS_DMA_LEN, TX_BUF_LEN) == 0); | |
696 | if (FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN_W1T)) { | |
697 | ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN, | |
698 | FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN)); | |
699 | } else { | |
700 | bus->regs[R_I2CS_DMA_LEN] = value; | |
701 | } | |
702 | break; | |
703 | case A_I2CS_CMD: | |
704 | if (FIELD_EX32(value, I2CS_CMD, W1_CTRL)) { | |
705 | bus->regs[R_I2CS_CMD] |= value; | |
706 | } else { | |
707 | bus->regs[R_I2CS_CMD] = value; | |
708 | } | |
709 | i2c_slave_set_address(bus->slave, bus->regs[R_I2CS_DEV_ADDR]); | |
710 | break; | |
ba2cccd6 | 711 | case A_I2CS_INTR_CTRL: |
1c5d909f PD |
712 | bus->regs[R_I2CS_INTR_CTRL] = value; |
713 | break; | |
714 | ||
ba2cccd6 | 715 | case A_I2CS_INTR_STS: |
1c5d909f PD |
716 | if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_CTRL, PKT_CMD_DONE)) { |
717 | if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE) && | |
718 | FIELD_EX32(value, I2CS_INTR_STS, PKT_CMD_DONE)) { | |
719 | bus->regs[R_I2CS_INTR_STS] &= 0xfffc0000; | |
720 | } | |
721 | } else { | |
722 | bus->regs[R_I2CS_INTR_STS] &= ~value; | |
723 | } | |
724 | if (!bus->regs[R_I2CS_INTR_STS]) { | |
725 | bus->controller->intr_status &= ~(1 << bus->id); | |
726 | qemu_irq_lower(aic->bus_get_irq(bus)); | |
727 | } | |
728 | aspeed_i2c_bus_raise_interrupt(bus); | |
729 | break; | |
730 | case A_I2CS_DMA_LEN_STS: | |
731 | bus->regs[R_I2CS_DMA_LEN_STS] = 0; | |
732 | break; | |
733 | case A_I2CS_DMA_TX_ADDR: | |
734 | qemu_log_mask(LOG_UNIMP, "%s: Slave mode DMA TX is not implemented\n", | |
ba2cccd6 JK |
735 | __func__); |
736 | break; | |
737 | default: | |
738 | qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", | |
739 | __func__, offset); | |
740 | } | |
741 | } | |
742 | ||
743 | static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset, | |
744 | uint64_t value, unsigned size) | |
16020011 | 745 | { |
51dd4923 | 746 | AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); |
bb626e5b | 747 | bool handle_rx; |
16020011 | 748 | |
66cc84a1 CLG |
749 | trace_aspeed_i2c_bus_write(bus->id, offset, size, value); |
750 | ||
16020011 | 751 | switch (offset) { |
3be3d6cc | 752 | case A_I2CD_FUN_CTRL: |
ba2cccd6 | 753 | if (SHARED_FIELD_EX32(value, SLAVE_EN)) { |
a8d48f59 | 754 | i2c_slave_set_address(bus->slave, bus->regs[R_I2CD_DEV_ADDR]); |
16020011 | 755 | } |
2260fc6f | 756 | bus->regs[R_I2CD_FUN_CTRL] = value & 0x0071C3FF; |
16020011 | 757 | break; |
3be3d6cc | 758 | case A_I2CD_AC_TIMING1: |
2260fc6f | 759 | bus->regs[R_I2CD_AC_TIMING1] = value & 0xFFFFF0F; |
16020011 | 760 | break; |
3be3d6cc | 761 | case A_I2CD_AC_TIMING2: |
2260fc6f | 762 | bus->regs[R_I2CD_AC_TIMING2] = value & 0x7; |
16020011 | 763 | break; |
3be3d6cc | 764 | case A_I2CD_INTR_CTRL: |
2260fc6f | 765 | bus->regs[R_I2CD_INTR_CTRL] = value & 0x7FFF; |
16020011 | 766 | break; |
3be3d6cc | 767 | case A_I2CD_INTR_STS: |
ba2cccd6 JK |
768 | handle_rx = SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_INTR_STS, RX_DONE) |
769 | && SHARED_FIELD_EX32(value, RX_DONE); | |
2260fc6f JK |
770 | bus->regs[R_I2CD_INTR_STS] &= ~(value & 0x7FFF); |
771 | if (!bus->regs[R_I2CD_INTR_STS]) { | |
5540cb97 | 772 | bus->controller->intr_status &= ~(1 << bus->id); |
51dd4923 | 773 | qemu_irq_lower(aic->bus_get_irq(bus)); |
5540cb97 | 774 | } |
a8d48f59 KJ |
775 | if (handle_rx) { |
776 | if (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, M_RX_CMD) || | |
777 | SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, | |
778 | M_S_RX_CMD_LAST)) { | |
779 | aspeed_i2c_handle_rx_cmd(bus); | |
780 | aspeed_i2c_bus_raise_interrupt(bus); | |
781 | } else if (aspeed_i2c_get_state(bus) == I2CD_STXD) { | |
782 | i2c_ack(bus->bus); | |
783 | } | |
bb626e5b | 784 | } |
16020011 | 785 | break; |
3be3d6cc | 786 | case A_I2CD_DEV_ADDR: |
d72a712c | 787 | bus->regs[R_I2CD_DEV_ADDR] = value; |
16020011 | 788 | break; |
3be3d6cc | 789 | case A_I2CD_POOL_CTRL: |
2260fc6f JK |
790 | bus->regs[R_I2CD_POOL_CTRL] &= ~0xffffff; |
791 | bus->regs[R_I2CD_POOL_CTRL] |= (value & 0xffffff); | |
6054fc73 CLG |
792 | break; |
793 | ||
3be3d6cc | 794 | case A_I2CD_BYTE_BUF: |
ba2cccd6 | 795 | SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CD_BYTE_BUF, TX_BUF, value); |
16020011 | 796 | break; |
3be3d6cc | 797 | case A_I2CD_CMD: |
16020011 CLG |
798 | if (!aspeed_i2c_bus_is_enabled(bus)) { |
799 | break; | |
800 | } | |
801 | ||
802 | if (!aspeed_i2c_bus_is_master(bus)) { | |
0c0f1bee | 803 | qemu_log_mask(LOG_GUEST_ERROR, "%s: Master mode is not enabled\n", |
16020011 CLG |
804 | __func__); |
805 | break; | |
806 | } | |
807 | ||
545d6bef | 808 | if (!aic->has_dma && |
ba2cccd6 JK |
809 | (SHARED_FIELD_EX32(value, RX_DMA_EN) || |
810 | SHARED_FIELD_EX32(value, TX_DMA_EN))) { | |
545d6bef CLG |
811 | qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); |
812 | break; | |
813 | } | |
814 | ||
ba2cccd6 JK |
815 | bus->regs[R_I2CD_CMD] &= ~0xFFFF; |
816 | bus->regs[R_I2CD_CMD] |= value & 0xFFFF; | |
817 | ||
16020011 | 818 | aspeed_i2c_bus_handle_cmd(bus, value); |
ddabca75 | 819 | aspeed_i2c_bus_raise_interrupt(bus); |
16020011 | 820 | break; |
3be3d6cc | 821 | case A_I2CD_DMA_ADDR: |
545d6bef CLG |
822 | if (!aic->has_dma) { |
823 | qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); | |
824 | break; | |
825 | } | |
826 | ||
2260fc6f | 827 | bus->regs[R_I2CD_DMA_ADDR] = value & 0x3ffffffc; |
545d6bef CLG |
828 | break; |
829 | ||
3be3d6cc | 830 | case A_I2CD_DMA_LEN: |
545d6bef CLG |
831 | if (!aic->has_dma) { |
832 | qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); | |
833 | break; | |
834 | } | |
835 | ||
2260fc6f JK |
836 | bus->regs[R_I2CD_DMA_LEN] = value & 0xfff; |
837 | if (!bus->regs[R_I2CD_DMA_LEN]) { | |
545d6bef CLG |
838 | qemu_log_mask(LOG_UNIMP, "%s: invalid DMA length\n", __func__); |
839 | } | |
840 | break; | |
16020011 CLG |
841 | |
842 | default: | |
843 | qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", | |
844 | __func__, offset); | |
845 | } | |
846 | } | |
847 | ||
ba2cccd6 JK |
848 | static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, |
849 | uint64_t value, unsigned size) | |
850 | { | |
851 | AspeedI2CBus *bus = opaque; | |
852 | if (aspeed_i2c_is_new_mode(bus->controller)) { | |
853 | aspeed_i2c_bus_new_write(bus, offset, value, size); | |
854 | } else { | |
855 | aspeed_i2c_bus_old_write(bus, offset, value, size); | |
856 | } | |
857 | } | |
858 | ||
16020011 CLG |
859 | static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr offset, |
860 | unsigned size) | |
861 | { | |
862 | AspeedI2CState *s = opaque; | |
863 | ||
864 | switch (offset) { | |
3be3d6cc | 865 | case A_I2C_CTRL_STATUS: |
16020011 | 866 | return s->intr_status; |
3be3d6cc | 867 | case A_I2C_CTRL_GLOBAL: |
aab90b1c | 868 | return s->ctrl_global; |
ba2cccd6 JK |
869 | case A_I2C_CTRL_NEW_CLK_DIVIDER: |
870 | if (aspeed_i2c_is_new_mode(s)) { | |
871 | return s->new_clk_divider; | |
872 | } | |
873 | qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", | |
874 | __func__, offset); | |
875 | break; | |
16020011 CLG |
876 | default: |
877 | qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", | |
878 | __func__, offset); | |
879 | break; | |
880 | } | |
881 | ||
882 | return -1; | |
883 | } | |
884 | ||
885 | static void aspeed_i2c_ctrl_write(void *opaque, hwaddr offset, | |
886 | uint64_t value, unsigned size) | |
887 | { | |
aab90b1c CLG |
888 | AspeedI2CState *s = opaque; |
889 | ||
16020011 | 890 | switch (offset) { |
3be3d6cc | 891 | case A_I2C_CTRL_GLOBAL: |
aab90b1c CLG |
892 | s->ctrl_global = value; |
893 | break; | |
ba2cccd6 JK |
894 | case A_I2C_CTRL_NEW_CLK_DIVIDER: |
895 | if (aspeed_i2c_is_new_mode(s)) { | |
896 | s->new_clk_divider = value; | |
897 | } else { | |
898 | qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx | |
899 | "\n", __func__, offset); | |
900 | } | |
901 | break; | |
3be3d6cc | 902 | case A_I2C_CTRL_STATUS: |
16020011 CLG |
903 | default: |
904 | qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", | |
905 | __func__, offset); | |
906 | break; | |
907 | } | |
908 | } | |
909 | ||
910 | static const MemoryRegionOps aspeed_i2c_bus_ops = { | |
911 | .read = aspeed_i2c_bus_read, | |
912 | .write = aspeed_i2c_bus_write, | |
913 | .endianness = DEVICE_LITTLE_ENDIAN, | |
914 | }; | |
915 | ||
916 | static const MemoryRegionOps aspeed_i2c_ctrl_ops = { | |
917 | .read = aspeed_i2c_ctrl_read, | |
918 | .write = aspeed_i2c_ctrl_write, | |
919 | .endianness = DEVICE_LITTLE_ENDIAN, | |
920 | }; | |
921 | ||
6054fc73 CLG |
922 | static uint64_t aspeed_i2c_pool_read(void *opaque, hwaddr offset, |
923 | unsigned size) | |
924 | { | |
925 | AspeedI2CState *s = opaque; | |
926 | uint64_t ret = 0; | |
927 | int i; | |
928 | ||
929 | for (i = 0; i < size; i++) { | |
930 | ret |= (uint64_t) s->pool[offset + i] << (8 * i); | |
931 | } | |
932 | ||
933 | return ret; | |
934 | } | |
935 | ||
936 | static void aspeed_i2c_pool_write(void *opaque, hwaddr offset, | |
937 | uint64_t value, unsigned size) | |
938 | { | |
939 | AspeedI2CState *s = opaque; | |
940 | int i; | |
941 | ||
942 | for (i = 0; i < size; i++) { | |
943 | s->pool[offset + i] = (value >> (8 * i)) & 0xFF; | |
944 | } | |
945 | } | |
946 | ||
947 | static const MemoryRegionOps aspeed_i2c_pool_ops = { | |
948 | .read = aspeed_i2c_pool_read, | |
949 | .write = aspeed_i2c_pool_write, | |
950 | .endianness = DEVICE_LITTLE_ENDIAN, | |
951 | .valid = { | |
952 | .min_access_size = 1, | |
953 | .max_access_size = 4, | |
954 | }, | |
955 | }; | |
956 | ||
16020011 CLG |
957 | static const VMStateDescription aspeed_i2c_bus_vmstate = { |
958 | .name = TYPE_ASPEED_I2C, | |
ba2cccd6 JK |
959 | .version_id = 5, |
960 | .minimum_version_id = 5, | |
16020011 | 961 | .fields = (VMStateField[]) { |
ba2cccd6 | 962 | VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_NEW_NUM_REG), |
16020011 CLG |
963 | VMSTATE_END_OF_LIST() |
964 | } | |
965 | }; | |
966 | ||
967 | static const VMStateDescription aspeed_i2c_vmstate = { | |
968 | .name = TYPE_ASPEED_I2C, | |
6054fc73 CLG |
969 | .version_id = 2, |
970 | .minimum_version_id = 2, | |
16020011 CLG |
971 | .fields = (VMStateField[]) { |
972 | VMSTATE_UINT32(intr_status, AspeedI2CState), | |
973 | VMSTATE_STRUCT_ARRAY(busses, AspeedI2CState, | |
974 | ASPEED_I2C_NR_BUSSES, 1, aspeed_i2c_bus_vmstate, | |
975 | AspeedI2CBus), | |
6054fc73 | 976 | VMSTATE_UINT8_ARRAY(pool, AspeedI2CState, ASPEED_I2C_MAX_POOL_SIZE), |
16020011 CLG |
977 | VMSTATE_END_OF_LIST() |
978 | } | |
979 | }; | |
980 | ||
981 | static void aspeed_i2c_reset(DeviceState *dev) | |
982 | { | |
16020011 CLG |
983 | AspeedI2CState *s = ASPEED_I2C(dev); |
984 | ||
985 | s->intr_status = 0; | |
60261038 CLG |
986 | } |
987 | ||
988 | static void aspeed_i2c_instance_init(Object *obj) | |
989 | { | |
990 | AspeedI2CState *s = ASPEED_I2C(obj); | |
991 | AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); | |
992 | int i; | |
16020011 | 993 | |
f7da1aa8 | 994 | for (i = 0; i < aic->num_busses; i++) { |
60261038 CLG |
995 | object_initialize_child(obj, "bus[*]", &s->busses[i], |
996 | TYPE_ASPEED_I2C_BUS); | |
16020011 CLG |
997 | } |
998 | } | |
999 | ||
1000 | /* | |
f7da1aa8 | 1001 | * Address Definitions (AST2400 and AST2500) |
16020011 CLG |
1002 | * |
1003 | * 0x000 ... 0x03F: Global Register | |
1004 | * 0x040 ... 0x07F: Device 1 | |
1005 | * 0x080 ... 0x0BF: Device 2 | |
1006 | * 0x0C0 ... 0x0FF: Device 3 | |
1007 | * 0x100 ... 0x13F: Device 4 | |
1008 | * 0x140 ... 0x17F: Device 5 | |
1009 | * 0x180 ... 0x1BF: Device 6 | |
1010 | * 0x1C0 ... 0x1FF: Device 7 | |
1011 | * 0x200 ... 0x2FF: Buffer Pool (unused in linux driver) | |
1012 | * 0x300 ... 0x33F: Device 8 | |
1013 | * 0x340 ... 0x37F: Device 9 | |
1014 | * 0x380 ... 0x3BF: Device 10 | |
1015 | * 0x3C0 ... 0x3FF: Device 11 | |
1016 | * 0x400 ... 0x43F: Device 12 | |
1017 | * 0x440 ... 0x47F: Device 13 | |
1018 | * 0x480 ... 0x4BF: Device 14 | |
1019 | * 0x800 ... 0xFFF: Buffer Pool (unused in linux driver) | |
1020 | */ | |
1021 | static void aspeed_i2c_realize(DeviceState *dev, Error **errp) | |
1022 | { | |
1023 | int i; | |
1024 | SysBusDevice *sbd = SYS_BUS_DEVICE(dev); | |
1025 | AspeedI2CState *s = ASPEED_I2C(dev); | |
f7da1aa8 | 1026 | AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); |
16020011 CLG |
1027 | |
1028 | sysbus_init_irq(sbd, &s->irq); | |
1029 | memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s, | |
1030 | "aspeed.i2c", 0x1000); | |
1031 | sysbus_init_mmio(sbd, &s->iomem); | |
1032 | ||
f7da1aa8 | 1033 | for (i = 0; i < aic->num_busses; i++) { |
60261038 | 1034 | Object *bus = OBJECT(&s->busses[i]); |
f7da1aa8 | 1035 | int offset = i < aic->gap ? 1 : 5; |
51dd4923 | 1036 | |
60261038 CLG |
1037 | if (!object_property_set_link(bus, "controller", OBJECT(s), errp)) { |
1038 | return; | |
1039 | } | |
1040 | ||
1041 | if (!object_property_set_uint(bus, "bus-id", i, errp)) { | |
1042 | return; | |
1043 | } | |
1044 | ||
1045 | if (!sysbus_realize(SYS_BUS_DEVICE(bus), errp)) { | |
1046 | return; | |
1047 | } | |
1048 | ||
f7da1aa8 | 1049 | memory_region_add_subregion(&s->iomem, aic->reg_size * (i + offset), |
16020011 CLG |
1050 | &s->busses[i].mr); |
1051 | } | |
6054fc73 CLG |
1052 | |
1053 | memory_region_init_io(&s->pool_iomem, OBJECT(s), &aspeed_i2c_pool_ops, s, | |
1054 | "aspeed.i2c-pool", aic->pool_size); | |
1055 | memory_region_add_subregion(&s->iomem, aic->pool_base, &s->pool_iomem); | |
545d6bef CLG |
1056 | |
1057 | if (aic->has_dma) { | |
1058 | if (!s->dram_mr) { | |
1059 | error_setg(errp, TYPE_ASPEED_I2C ": 'dram' link not set"); | |
1060 | return; | |
1061 | } | |
1062 | ||
3f7a53b2 CLG |
1063 | address_space_init(&s->dram_as, s->dram_mr, |
1064 | TYPE_ASPEED_I2C "-dma-dram"); | |
545d6bef | 1065 | } |
16020011 CLG |
1066 | } |
1067 | ||
545d6bef CLG |
1068 | static Property aspeed_i2c_properties[] = { |
1069 | DEFINE_PROP_LINK("dram", AspeedI2CState, dram_mr, | |
1070 | TYPE_MEMORY_REGION, MemoryRegion *), | |
1071 | DEFINE_PROP_END_OF_LIST(), | |
1072 | }; | |
1073 | ||
16020011 CLG |
1074 | static void aspeed_i2c_class_init(ObjectClass *klass, void *data) |
1075 | { | |
1076 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1077 | ||
1078 | dc->vmsd = &aspeed_i2c_vmstate; | |
1079 | dc->reset = aspeed_i2c_reset; | |
4f67d30b | 1080 | device_class_set_props(dc, aspeed_i2c_properties); |
16020011 CLG |
1081 | dc->realize = aspeed_i2c_realize; |
1082 | dc->desc = "Aspeed I2C Controller"; | |
1083 | } | |
1084 | ||
1085 | static const TypeInfo aspeed_i2c_info = { | |
1086 | .name = TYPE_ASPEED_I2C, | |
1087 | .parent = TYPE_SYS_BUS_DEVICE, | |
60261038 | 1088 | .instance_init = aspeed_i2c_instance_init, |
16020011 CLG |
1089 | .instance_size = sizeof(AspeedI2CState), |
1090 | .class_init = aspeed_i2c_class_init, | |
f7da1aa8 CLG |
1091 | .class_size = sizeof(AspeedI2CClass), |
1092 | .abstract = true, | |
1093 | }; | |
1094 | ||
1c5d909f PD |
1095 | static int aspeed_i2c_bus_new_slave_event(AspeedI2CBus *bus, |
1096 | enum i2c_event event) | |
1097 | { | |
1098 | switch (event) { | |
1099 | case I2C_START_SEND_ASYNC: | |
1100 | if (!SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CS_CMD, RX_DMA_EN)) { | |
1101 | qemu_log_mask(LOG_GUEST_ERROR, | |
1102 | "%s: Slave mode RX DMA is not enabled\n", __func__); | |
1103 | return -1; | |
1104 | } | |
1105 | ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 0); | |
1106 | bus->regs[R_I2CC_DMA_ADDR] = | |
1107 | ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR); | |
1108 | bus->regs[R_I2CC_DMA_LEN] = | |
1109 | ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN) + 1; | |
1110 | i2c_ack(bus->bus); | |
1111 | break; | |
1112 | case I2C_FINISH: | |
1113 | ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE, 1); | |
1114 | ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, SLAVE_ADDR_RX_MATCH, 1); | |
1115 | SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, NORMAL_STOP, 1); | |
1116 | SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, RX_DONE, 1); | |
1117 | aspeed_i2c_bus_raise_slave_interrupt(bus); | |
1118 | break; | |
1119 | default: | |
1120 | qemu_log_mask(LOG_UNIMP, "%s: i2c event %d unimplemented\n", | |
1121 | __func__, event); | |
1122 | return -1; | |
1123 | } | |
1124 | ||
1125 | return 0; | |
1126 | } | |
1127 | ||
a8d48f59 KJ |
1128 | static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event) |
1129 | { | |
1130 | BusState *qbus = qdev_get_parent_bus(DEVICE(slave)); | |
1131 | AspeedI2CBus *bus = ASPEED_I2C_BUS(qbus->parent); | |
1132 | uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); | |
1133 | uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); | |
3648d31f PD |
1134 | uint32_t reg_dev_addr = aspeed_i2c_bus_dev_addr_offset(bus); |
1135 | uint32_t dev_addr = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_dev_addr, | |
1136 | SLAVE_DEV_ADDR1); | |
a8d48f59 | 1137 | |
1c5d909f PD |
1138 | if (aspeed_i2c_is_new_mode(bus->controller)) { |
1139 | return aspeed_i2c_bus_new_slave_event(bus, event); | |
1140 | } | |
1141 | ||
a8d48f59 KJ |
1142 | switch (event) { |
1143 | case I2C_START_SEND_ASYNC: | |
3648d31f PD |
1144 | /* Bit[0] == 0 indicates "send". */ |
1145 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, dev_addr << 1); | |
a8d48f59 KJ |
1146 | |
1147 | ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH, 1); | |
1148 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); | |
1149 | ||
1150 | aspeed_i2c_set_state(bus, I2CD_STXD); | |
1151 | ||
1152 | break; | |
1153 | ||
1154 | case I2C_FINISH: | |
1155 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, NORMAL_STOP, 1); | |
1156 | ||
1157 | aspeed_i2c_set_state(bus, I2CD_IDLE); | |
1158 | ||
1159 | break; | |
1160 | ||
1161 | default: | |
1162 | return -1; | |
1163 | } | |
1164 | ||
1165 | aspeed_i2c_bus_raise_interrupt(bus); | |
1166 | ||
1167 | return 0; | |
1168 | } | |
1169 | ||
1c5d909f PD |
1170 | static void aspeed_i2c_bus_new_slave_send_async(AspeedI2CBus *bus, uint8_t data) |
1171 | { | |
1172 | assert(address_space_write(&bus->controller->dram_as, | |
1173 | bus->regs[R_I2CC_DMA_ADDR], | |
1174 | MEMTXATTRS_UNSPECIFIED, &data, 1) == MEMTX_OK); | |
1175 | ||
1176 | bus->regs[R_I2CC_DMA_ADDR]++; | |
1177 | bus->regs[R_I2CC_DMA_LEN]--; | |
1178 | ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, | |
1179 | ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN) + 1); | |
1180 | i2c_ack(bus->bus); | |
1181 | } | |
1182 | ||
a8d48f59 KJ |
1183 | static void aspeed_i2c_bus_slave_send_async(I2CSlave *slave, uint8_t data) |
1184 | { | |
1185 | BusState *qbus = qdev_get_parent_bus(DEVICE(slave)); | |
1186 | AspeedI2CBus *bus = ASPEED_I2C_BUS(qbus->parent); | |
1187 | uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); | |
1188 | uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); | |
1189 | ||
1c5d909f PD |
1190 | if (aspeed_i2c_is_new_mode(bus->controller)) { |
1191 | return aspeed_i2c_bus_new_slave_send_async(bus, data); | |
1192 | } | |
1193 | ||
a8d48f59 KJ |
1194 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data); |
1195 | SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); | |
1196 | ||
1197 | aspeed_i2c_bus_raise_interrupt(bus); | |
1198 | } | |
1199 | ||
1200 | static void aspeed_i2c_bus_slave_class_init(ObjectClass *klass, void *data) | |
1201 | { | |
1202 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1203 | I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); | |
1204 | ||
1205 | dc->desc = "Aspeed I2C Bus Slave"; | |
1206 | ||
1207 | sc->event = aspeed_i2c_bus_slave_event; | |
1208 | sc->send_async = aspeed_i2c_bus_slave_send_async; | |
1209 | } | |
1210 | ||
1211 | static const TypeInfo aspeed_i2c_bus_slave_info = { | |
1212 | .name = TYPE_ASPEED_I2C_BUS_SLAVE, | |
1213 | .parent = TYPE_I2C_SLAVE, | |
1214 | .instance_size = sizeof(AspeedI2CBusSlave), | |
1215 | .class_init = aspeed_i2c_bus_slave_class_init, | |
1216 | }; | |
1217 | ||
60261038 CLG |
1218 | static void aspeed_i2c_bus_reset(DeviceState *dev) |
1219 | { | |
1220 | AspeedI2CBus *s = ASPEED_I2C_BUS(dev); | |
1221 | ||
2260fc6f | 1222 | memset(s->regs, 0, sizeof(s->regs)); |
60261038 CLG |
1223 | i2c_end_transfer(s->bus); |
1224 | } | |
1225 | ||
1226 | static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp) | |
1227 | { | |
1228 | AspeedI2CBus *s = ASPEED_I2C_BUS(dev); | |
1229 | AspeedI2CClass *aic; | |
1230 | g_autofree char *name = g_strdup_printf(TYPE_ASPEED_I2C_BUS ".%d", s->id); | |
1231 | ||
1232 | if (!s->controller) { | |
1233 | error_setg(errp, TYPE_ASPEED_I2C_BUS ": 'controller' link not set"); | |
1234 | return; | |
1235 | } | |
1236 | ||
1237 | aic = ASPEED_I2C_GET_CLASS(s->controller); | |
1238 | ||
1239 | sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); | |
1240 | ||
1241 | s->bus = i2c_init_bus(dev, name); | |
a8d48f59 KJ |
1242 | s->slave = i2c_slave_create_simple(s->bus, TYPE_ASPEED_I2C_BUS_SLAVE, |
1243 | 0xff); | |
60261038 CLG |
1244 | |
1245 | memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops, | |
1246 | s, name, aic->reg_size); | |
1247 | sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr); | |
1248 | } | |
1249 | ||
1250 | static Property aspeed_i2c_bus_properties[] = { | |
1251 | DEFINE_PROP_UINT8("bus-id", AspeedI2CBus, id, 0), | |
1252 | DEFINE_PROP_LINK("controller", AspeedI2CBus, controller, TYPE_ASPEED_I2C, | |
1253 | AspeedI2CState *), | |
1254 | DEFINE_PROP_END_OF_LIST(), | |
1255 | }; | |
1256 | ||
1257 | static void aspeed_i2c_bus_class_init(ObjectClass *klass, void *data) | |
1258 | { | |
1259 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1260 | ||
1261 | dc->desc = "Aspeed I2C Bus"; | |
1262 | dc->realize = aspeed_i2c_bus_realize; | |
1263 | dc->reset = aspeed_i2c_bus_reset; | |
1264 | device_class_set_props(dc, aspeed_i2c_bus_properties); | |
1265 | } | |
1266 | ||
1267 | static const TypeInfo aspeed_i2c_bus_info = { | |
1268 | .name = TYPE_ASPEED_I2C_BUS, | |
1269 | .parent = TYPE_SYS_BUS_DEVICE, | |
1270 | .instance_size = sizeof(AspeedI2CBus), | |
1271 | .class_init = aspeed_i2c_bus_class_init, | |
1272 | }; | |
1273 | ||
51dd4923 CLG |
1274 | static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus) |
1275 | { | |
1276 | return bus->controller->irq; | |
1277 | } | |
1278 | ||
6054fc73 CLG |
1279 | static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus) |
1280 | { | |
1281 | uint8_t *pool_page = | |
2260fc6f JK |
1282 | &bus->controller->pool[ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL, |
1283 | POOL_PAGE_SEL) * 0x100]; | |
6054fc73 | 1284 | |
2260fc6f | 1285 | return &pool_page[ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, OFFSET)]; |
6054fc73 CLG |
1286 | } |
1287 | ||
f7da1aa8 CLG |
1288 | static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data) |
1289 | { | |
1290 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1291 | AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); | |
1292 | ||
1293 | dc->desc = "ASPEED 2400 I2C Controller"; | |
1294 | ||
1295 | aic->num_busses = 14; | |
1296 | aic->reg_size = 0x40; | |
1297 | aic->gap = 7; | |
51dd4923 | 1298 | aic->bus_get_irq = aspeed_2400_i2c_bus_get_irq; |
6054fc73 CLG |
1299 | aic->pool_size = 0x800; |
1300 | aic->pool_base = 0x800; | |
1301 | aic->bus_pool_base = aspeed_2400_i2c_bus_pool_base; | |
f7da1aa8 CLG |
1302 | } |
1303 | ||
1304 | static const TypeInfo aspeed_2400_i2c_info = { | |
1305 | .name = TYPE_ASPEED_2400_I2C, | |
1306 | .parent = TYPE_ASPEED_I2C, | |
1307 | .class_init = aspeed_2400_i2c_class_init, | |
1308 | }; | |
1309 | ||
51dd4923 CLG |
1310 | static qemu_irq aspeed_2500_i2c_bus_get_irq(AspeedI2CBus *bus) |
1311 | { | |
1312 | return bus->controller->irq; | |
1313 | } | |
1314 | ||
6054fc73 CLG |
1315 | static uint8_t *aspeed_2500_i2c_bus_pool_base(AspeedI2CBus *bus) |
1316 | { | |
1317 | return &bus->controller->pool[bus->id * 0x10]; | |
1318 | } | |
1319 | ||
f7da1aa8 CLG |
1320 | static void aspeed_2500_i2c_class_init(ObjectClass *klass, void *data) |
1321 | { | |
1322 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1323 | AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); | |
1324 | ||
1325 | dc->desc = "ASPEED 2500 I2C Controller"; | |
1326 | ||
1327 | aic->num_busses = 14; | |
1328 | aic->reg_size = 0x40; | |
1329 | aic->gap = 7; | |
51dd4923 | 1330 | aic->bus_get_irq = aspeed_2500_i2c_bus_get_irq; |
6054fc73 CLG |
1331 | aic->pool_size = 0x100; |
1332 | aic->pool_base = 0x200; | |
1333 | aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base; | |
aab90b1c | 1334 | aic->check_sram = true; |
545d6bef | 1335 | aic->has_dma = true; |
f7da1aa8 CLG |
1336 | } |
1337 | ||
1338 | static const TypeInfo aspeed_2500_i2c_info = { | |
1339 | .name = TYPE_ASPEED_2500_I2C, | |
1340 | .parent = TYPE_ASPEED_I2C, | |
1341 | .class_init = aspeed_2500_i2c_class_init, | |
16020011 CLG |
1342 | }; |
1343 | ||
51dd4923 CLG |
1344 | static qemu_irq aspeed_2600_i2c_bus_get_irq(AspeedI2CBus *bus) |
1345 | { | |
1346 | return bus->irq; | |
1347 | } | |
1348 | ||
6054fc73 CLG |
1349 | static uint8_t *aspeed_2600_i2c_bus_pool_base(AspeedI2CBus *bus) |
1350 | { | |
1351 | return &bus->controller->pool[bus->id * 0x20]; | |
1352 | } | |
1353 | ||
51dd4923 CLG |
1354 | static void aspeed_2600_i2c_class_init(ObjectClass *klass, void *data) |
1355 | { | |
1356 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1357 | AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); | |
1358 | ||
1359 | dc->desc = "ASPEED 2600 I2C Controller"; | |
1360 | ||
1361 | aic->num_busses = 16; | |
1362 | aic->reg_size = 0x80; | |
1363 | aic->gap = -1; /* no gap */ | |
1364 | aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq; | |
6054fc73 CLG |
1365 | aic->pool_size = 0x200; |
1366 | aic->pool_base = 0xC00; | |
1367 | aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base; | |
545d6bef | 1368 | aic->has_dma = true; |
51dd4923 CLG |
1369 | } |
1370 | ||
1371 | static const TypeInfo aspeed_2600_i2c_info = { | |
1372 | .name = TYPE_ASPEED_2600_I2C, | |
1373 | .parent = TYPE_ASPEED_I2C, | |
1374 | .class_init = aspeed_2600_i2c_class_init, | |
1375 | }; | |
1376 | ||
b35802ce CLG |
1377 | static void aspeed_1030_i2c_class_init(ObjectClass *klass, void *data) |
1378 | { | |
1379 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1380 | AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); | |
1381 | ||
1382 | dc->desc = "ASPEED 1030 I2C Controller"; | |
1383 | ||
1384 | aic->num_busses = 14; | |
1385 | aic->reg_size = 0x80; | |
1386 | aic->gap = -1; /* no gap */ | |
1387 | aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq; | |
1388 | aic->pool_size = 0x200; | |
1389 | aic->pool_base = 0xC00; | |
1390 | aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base; | |
1391 | aic->has_dma = true; | |
1392 | } | |
1393 | ||
1394 | static const TypeInfo aspeed_1030_i2c_info = { | |
1395 | .name = TYPE_ASPEED_1030_I2C, | |
1396 | .parent = TYPE_ASPEED_I2C, | |
1397 | .class_init = aspeed_1030_i2c_class_init, | |
1398 | }; | |
1399 | ||
16020011 CLG |
1400 | static void aspeed_i2c_register_types(void) |
1401 | { | |
60261038 | 1402 | type_register_static(&aspeed_i2c_bus_info); |
a8d48f59 | 1403 | type_register_static(&aspeed_i2c_bus_slave_info); |
16020011 | 1404 | type_register_static(&aspeed_i2c_info); |
f7da1aa8 CLG |
1405 | type_register_static(&aspeed_2400_i2c_info); |
1406 | type_register_static(&aspeed_2500_i2c_info); | |
51dd4923 | 1407 | type_register_static(&aspeed_2600_i2c_info); |
b35802ce | 1408 | type_register_static(&aspeed_1030_i2c_info); |
16020011 CLG |
1409 | } |
1410 | ||
1411 | type_init(aspeed_i2c_register_types) | |
1412 | ||
1413 | ||
7a204cbd | 1414 | I2CBus *aspeed_i2c_get_bus(AspeedI2CState *s, int busnr) |
16020011 | 1415 | { |
f7da1aa8 | 1416 | AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); |
16020011 CLG |
1417 | I2CBus *bus = NULL; |
1418 | ||
f7da1aa8 | 1419 | if (busnr >= 0 && busnr < aic->num_busses) { |
16020011 CLG |
1420 | bus = s->busses[busnr].bus; |
1421 | } | |
1422 | ||
1423 | return bus; | |
1424 | } |