]>
Commit | Line | Data |
---|---|---|
9be8a82c SJ |
1 | /* |
2 | * Allwinner I2C Bus Serial Interface Emulation | |
3 | * | |
4 | * Copyright (C) 2022 Strahinja Jankovic <strahinja.p.jankovic@gmail.com> | |
5 | * | |
6 | * This file is derived from IMX I2C controller, | |
7 | * by Jean-Christophe DUBOIS . | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify it | |
10 | * under the terms of the GNU General Public License as published by the | |
11 | * Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 | * for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License along | |
20 | * with this program; if not, see <http://www.gnu.org/licenses/>. | |
21 | * | |
22 | * SPDX-License-Identifier: MIT | |
23 | */ | |
24 | ||
25 | #include "qemu/osdep.h" | |
26 | #include "hw/i2c/allwinner-i2c.h" | |
27 | #include "hw/irq.h" | |
28 | #include "migration/vmstate.h" | |
29 | #include "hw/i2c/i2c.h" | |
30 | #include "qemu/log.h" | |
31 | #include "trace.h" | |
32 | #include "qemu/module.h" | |
33 | ||
34 | /* Allwinner I2C memory map */ | |
35 | #define TWI_ADDR_REG 0x00 /* slave address register */ | |
36 | #define TWI_XADDR_REG 0x04 /* extended slave address register */ | |
37 | #define TWI_DATA_REG 0x08 /* data register */ | |
38 | #define TWI_CNTR_REG 0x0c /* control register */ | |
39 | #define TWI_STAT_REG 0x10 /* status register */ | |
40 | #define TWI_CCR_REG 0x14 /* clock control register */ | |
41 | #define TWI_SRST_REG 0x18 /* software reset register */ | |
42 | #define TWI_EFR_REG 0x1c /* enhance feature register */ | |
43 | #define TWI_LCR_REG 0x20 /* line control register */ | |
44 | ||
45 | /* Used only in slave mode, do not set */ | |
46 | #define TWI_ADDR_RESET 0 | |
47 | #define TWI_XADDR_RESET 0 | |
48 | ||
49 | /* Data register */ | |
50 | #define TWI_DATA_MASK 0xFF | |
51 | #define TWI_DATA_RESET 0 | |
52 | ||
53 | /* Control register */ | |
54 | #define TWI_CNTR_INT_EN (1 << 7) | |
55 | #define TWI_CNTR_BUS_EN (1 << 6) | |
56 | #define TWI_CNTR_M_STA (1 << 5) | |
57 | #define TWI_CNTR_M_STP (1 << 4) | |
58 | #define TWI_CNTR_INT_FLAG (1 << 3) | |
59 | #define TWI_CNTR_A_ACK (1 << 2) | |
60 | #define TWI_CNTR_MASK 0xFC | |
61 | #define TWI_CNTR_RESET 0 | |
62 | ||
63 | /* Status register */ | |
64 | #define TWI_STAT_MASK 0xF8 | |
65 | #define TWI_STAT_RESET 0xF8 | |
66 | ||
67 | /* Clock register */ | |
68 | #define TWI_CCR_CLK_M_MASK 0x78 | |
69 | #define TWI_CCR_CLK_N_MASK 0x07 | |
70 | #define TWI_CCR_MASK 0x7F | |
71 | #define TWI_CCR_RESET 0 | |
72 | ||
73 | /* Soft reset */ | |
74 | #define TWI_SRST_MASK 0x01 | |
75 | #define TWI_SRST_RESET 0 | |
76 | ||
77 | /* Enhance feature */ | |
78 | #define TWI_EFR_MASK 0x03 | |
79 | #define TWI_EFR_RESET 0 | |
80 | ||
81 | /* Line control */ | |
82 | #define TWI_LCR_SCL_STATE (1 << 5) | |
83 | #define TWI_LCR_SDA_STATE (1 << 4) | |
84 | #define TWI_LCR_SCL_CTL (1 << 3) | |
85 | #define TWI_LCR_SCL_CTL_EN (1 << 2) | |
86 | #define TWI_LCR_SDA_CTL (1 << 1) | |
87 | #define TWI_LCR_SDA_CTL_EN (1 << 0) | |
88 | #define TWI_LCR_MASK 0x3F | |
89 | #define TWI_LCR_RESET 0x3A | |
90 | ||
91 | /* Status value in STAT register is shifted by 3 bits */ | |
92 | #define TWI_STAT_SHIFT 3 | |
93 | #define STAT_FROM_STA(x) ((x) << TWI_STAT_SHIFT) | |
94 | #define STAT_TO_STA(x) ((x) >> TWI_STAT_SHIFT) | |
95 | ||
96 | enum { | |
97 | STAT_BUS_ERROR = 0, | |
98 | /* Master mode */ | |
99 | STAT_M_STA_TX, | |
100 | STAT_M_RSTA_TX, | |
101 | STAT_M_ADDR_WR_ACK, | |
102 | STAT_M_ADDR_WR_NACK, | |
103 | STAT_M_DATA_TX_ACK, | |
104 | STAT_M_DATA_TX_NACK, | |
105 | STAT_M_ARB_LOST, | |
106 | STAT_M_ADDR_RD_ACK, | |
107 | STAT_M_ADDR_RD_NACK, | |
108 | STAT_M_DATA_RX_ACK, | |
109 | STAT_M_DATA_RX_NACK, | |
110 | /* Slave mode */ | |
111 | STAT_S_ADDR_WR_ACK, | |
112 | STAT_S_ARB_LOST_AW_ACK, | |
113 | STAT_S_GCA_ACK, | |
114 | STAT_S_ARB_LOST_GCA_ACK, | |
115 | STAT_S_DATA_RX_SA_ACK, | |
116 | STAT_S_DATA_RX_SA_NACK, | |
117 | STAT_S_DATA_RX_GCA_ACK, | |
118 | STAT_S_DATA_RX_GCA_NACK, | |
119 | STAT_S_STP_RSTA, | |
120 | STAT_S_ADDR_RD_ACK, | |
121 | STAT_S_ARB_LOST_AR_ACK, | |
122 | STAT_S_DATA_TX_ACK, | |
123 | STAT_S_DATA_TX_NACK, | |
124 | STAT_S_LB_TX_ACK, | |
125 | /* Master mode, 10-bit */ | |
126 | STAT_M_2ND_ADDR_WR_ACK, | |
127 | STAT_M_2ND_ADDR_WR_NACK, | |
128 | /* Idle */ | |
129 | STAT_IDLE = 0x1f | |
130 | } TWI_STAT_STA; | |
131 | ||
132 | static const char *allwinner_i2c_get_regname(unsigned offset) | |
133 | { | |
134 | switch (offset) { | |
135 | case TWI_ADDR_REG: | |
136 | return "ADDR"; | |
137 | case TWI_XADDR_REG: | |
138 | return "XADDR"; | |
139 | case TWI_DATA_REG: | |
140 | return "DATA"; | |
141 | case TWI_CNTR_REG: | |
142 | return "CNTR"; | |
143 | case TWI_STAT_REG: | |
144 | return "STAT"; | |
145 | case TWI_CCR_REG: | |
146 | return "CCR"; | |
147 | case TWI_SRST_REG: | |
148 | return "SRST"; | |
149 | case TWI_EFR_REG: | |
150 | return "EFR"; | |
151 | case TWI_LCR_REG: | |
152 | return "LCR"; | |
153 | default: | |
154 | return "[?]"; | |
155 | } | |
156 | } | |
157 | ||
158 | static inline bool allwinner_i2c_is_reset(AWI2CState *s) | |
159 | { | |
160 | return s->srst & TWI_SRST_MASK; | |
161 | } | |
162 | ||
163 | static inline bool allwinner_i2c_bus_is_enabled(AWI2CState *s) | |
164 | { | |
165 | return s->cntr & TWI_CNTR_BUS_EN; | |
166 | } | |
167 | ||
168 | static inline bool allwinner_i2c_interrupt_is_enabled(AWI2CState *s) | |
169 | { | |
170 | return s->cntr & TWI_CNTR_INT_EN; | |
171 | } | |
172 | ||
173 | static void allwinner_i2c_reset_hold(Object *obj) | |
174 | { | |
175 | AWI2CState *s = AW_I2C(obj); | |
176 | ||
177 | if (STAT_TO_STA(s->stat) != STAT_IDLE) { | |
178 | i2c_end_transfer(s->bus); | |
179 | } | |
180 | ||
181 | s->addr = TWI_ADDR_RESET; | |
182 | s->xaddr = TWI_XADDR_RESET; | |
183 | s->data = TWI_DATA_RESET; | |
184 | s->cntr = TWI_CNTR_RESET; | |
185 | s->stat = TWI_STAT_RESET; | |
186 | s->ccr = TWI_CCR_RESET; | |
187 | s->srst = TWI_SRST_RESET; | |
188 | s->efr = TWI_EFR_RESET; | |
189 | s->lcr = TWI_LCR_RESET; | |
190 | } | |
191 | ||
192 | static inline void allwinner_i2c_raise_interrupt(AWI2CState *s) | |
193 | { | |
194 | /* | |
195 | * Raise an interrupt if the device is not reset and it is configured | |
196 | * to generate some interrupts. | |
197 | */ | |
198 | if (!allwinner_i2c_is_reset(s) && allwinner_i2c_bus_is_enabled(s)) { | |
199 | if (STAT_TO_STA(s->stat) != STAT_IDLE) { | |
200 | s->cntr |= TWI_CNTR_INT_FLAG; | |
201 | if (allwinner_i2c_interrupt_is_enabled(s)) { | |
202 | qemu_irq_raise(s->irq); | |
203 | } | |
204 | } | |
205 | } | |
206 | } | |
207 | ||
208 | static uint64_t allwinner_i2c_read(void *opaque, hwaddr offset, | |
209 | unsigned size) | |
210 | { | |
211 | uint16_t value; | |
212 | AWI2CState *s = AW_I2C(opaque); | |
213 | ||
214 | switch (offset) { | |
215 | case TWI_ADDR_REG: | |
216 | value = s->addr; | |
217 | break; | |
218 | case TWI_XADDR_REG: | |
219 | value = s->xaddr; | |
220 | break; | |
221 | case TWI_DATA_REG: | |
222 | if ((STAT_TO_STA(s->stat) == STAT_M_ADDR_RD_ACK) || | |
223 | (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_ACK) || | |
224 | (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_NACK)) { | |
225 | /* Get the next byte */ | |
226 | s->data = i2c_recv(s->bus); | |
227 | ||
228 | if (s->cntr & TWI_CNTR_A_ACK) { | |
229 | s->stat = STAT_FROM_STA(STAT_M_DATA_RX_ACK); | |
230 | } else { | |
231 | s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK); | |
232 | } | |
233 | allwinner_i2c_raise_interrupt(s); | |
234 | } | |
235 | value = s->data; | |
236 | break; | |
237 | case TWI_CNTR_REG: | |
238 | value = s->cntr; | |
239 | break; | |
240 | case TWI_STAT_REG: | |
241 | value = s->stat; | |
242 | /* | |
243 | * If polling when reading then change state to indicate data | |
244 | * is available | |
245 | */ | |
246 | if (STAT_TO_STA(s->stat) == STAT_M_ADDR_RD_ACK) { | |
247 | if (s->cntr & TWI_CNTR_A_ACK) { | |
248 | s->stat = STAT_FROM_STA(STAT_M_DATA_RX_ACK); | |
249 | } else { | |
250 | s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK); | |
251 | } | |
252 | allwinner_i2c_raise_interrupt(s); | |
253 | } | |
254 | break; | |
255 | case TWI_CCR_REG: | |
256 | value = s->ccr; | |
257 | break; | |
258 | case TWI_SRST_REG: | |
259 | value = s->srst; | |
260 | break; | |
261 | case TWI_EFR_REG: | |
262 | value = s->efr; | |
263 | break; | |
264 | case TWI_LCR_REG: | |
265 | value = s->lcr; | |
266 | break; | |
267 | default: | |
268 | qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" | |
269 | HWADDR_PRIx "\n", TYPE_AW_I2C, __func__, offset); | |
270 | value = 0; | |
271 | break; | |
272 | } | |
273 | ||
274 | trace_allwinner_i2c_read(allwinner_i2c_get_regname(offset), offset, value); | |
275 | ||
276 | return (uint64_t)value; | |
277 | } | |
278 | ||
279 | static void allwinner_i2c_write(void *opaque, hwaddr offset, | |
280 | uint64_t value, unsigned size) | |
281 | { | |
282 | AWI2CState *s = AW_I2C(opaque); | |
283 | ||
284 | value &= 0xff; | |
285 | ||
286 | trace_allwinner_i2c_write(allwinner_i2c_get_regname(offset), offset, value); | |
287 | ||
288 | switch (offset) { | |
289 | case TWI_ADDR_REG: | |
290 | s->addr = (uint8_t)value; | |
291 | break; | |
292 | case TWI_XADDR_REG: | |
293 | s->xaddr = (uint8_t)value; | |
294 | break; | |
295 | case TWI_DATA_REG: | |
296 | /* If the device is in reset or not enabled, nothing to do */ | |
297 | if (allwinner_i2c_is_reset(s) || (!allwinner_i2c_bus_is_enabled(s))) { | |
298 | break; | |
299 | } | |
300 | ||
301 | s->data = value & TWI_DATA_MASK; | |
302 | ||
303 | switch (STAT_TO_STA(s->stat)) { | |
304 | case STAT_M_STA_TX: | |
305 | case STAT_M_RSTA_TX: | |
306 | /* Send address */ | |
307 | if (i2c_start_transfer(s->bus, extract32(s->data, 1, 7), | |
308 | extract32(s->data, 0, 1))) { | |
309 | /* If non zero is returned, the address is not valid */ | |
310 | s->stat = STAT_FROM_STA(STAT_M_ADDR_WR_NACK); | |
311 | } else { | |
312 | /* Determine if read of write */ | |
313 | if (extract32(s->data, 0, 1)) { | |
314 | s->stat = STAT_FROM_STA(STAT_M_ADDR_RD_ACK); | |
315 | } else { | |
316 | s->stat = STAT_FROM_STA(STAT_M_ADDR_WR_ACK); | |
317 | } | |
318 | allwinner_i2c_raise_interrupt(s); | |
319 | } | |
320 | break; | |
321 | case STAT_M_ADDR_WR_ACK: | |
322 | case STAT_M_DATA_TX_ACK: | |
323 | if (i2c_send(s->bus, s->data)) { | |
324 | /* If the target return non zero then end the transfer */ | |
325 | s->stat = STAT_FROM_STA(STAT_M_DATA_TX_NACK); | |
326 | i2c_end_transfer(s->bus); | |
327 | } else { | |
328 | s->stat = STAT_FROM_STA(STAT_M_DATA_TX_ACK); | |
329 | allwinner_i2c_raise_interrupt(s); | |
330 | } | |
331 | break; | |
332 | default: | |
333 | break; | |
334 | } | |
335 | break; | |
336 | case TWI_CNTR_REG: | |
337 | if (!allwinner_i2c_is_reset(s)) { | |
338 | /* Do something only if not in software reset */ | |
339 | s->cntr = value & TWI_CNTR_MASK; | |
340 | ||
341 | /* Check if start condition should be sent */ | |
342 | if (s->cntr & TWI_CNTR_M_STA) { | |
343 | /* Update status */ | |
344 | if (STAT_TO_STA(s->stat) == STAT_IDLE) { | |
345 | /* Send start condition */ | |
346 | s->stat = STAT_FROM_STA(STAT_M_STA_TX); | |
347 | } else { | |
348 | /* Send repeated start condition */ | |
349 | s->stat = STAT_FROM_STA(STAT_M_RSTA_TX); | |
350 | } | |
351 | /* Clear start condition */ | |
352 | s->cntr &= ~TWI_CNTR_M_STA; | |
353 | } | |
354 | if (s->cntr & TWI_CNTR_M_STP) { | |
355 | /* Update status */ | |
356 | i2c_end_transfer(s->bus); | |
357 | s->stat = STAT_FROM_STA(STAT_IDLE); | |
358 | s->cntr &= ~TWI_CNTR_M_STP; | |
359 | } | |
8461bfdc Z |
360 | |
361 | if (!s->irq_clear_inverted && !(s->cntr & TWI_CNTR_INT_FLAG)) { | |
362 | /* Write 0 to clear this flag */ | |
363 | qemu_irq_lower(s->irq); | |
364 | } else if (s->irq_clear_inverted && (s->cntr & TWI_CNTR_INT_FLAG)) { | |
365 | /* Write 1 to clear this flag */ | |
366 | s->cntr &= ~TWI_CNTR_INT_FLAG; | |
9be8a82c SJ |
367 | qemu_irq_lower(s->irq); |
368 | } | |
8461bfdc | 369 | |
9be8a82c SJ |
370 | if ((s->cntr & TWI_CNTR_A_ACK) == 0) { |
371 | if (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_ACK) { | |
372 | s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK); | |
373 | } | |
374 | } else { | |
375 | if (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_NACK) { | |
376 | s->stat = STAT_FROM_STA(STAT_M_DATA_RX_ACK); | |
377 | } | |
378 | } | |
379 | allwinner_i2c_raise_interrupt(s); | |
380 | ||
381 | } | |
382 | break; | |
383 | case TWI_CCR_REG: | |
384 | s->ccr = value & TWI_CCR_MASK; | |
385 | break; | |
386 | case TWI_SRST_REG: | |
387 | if (((value & TWI_SRST_MASK) == 0) && (s->srst & TWI_SRST_MASK)) { | |
388 | /* Perform reset */ | |
389 | allwinner_i2c_reset_hold(OBJECT(s)); | |
390 | } | |
391 | s->srst = value & TWI_SRST_MASK; | |
392 | break; | |
393 | case TWI_EFR_REG: | |
394 | s->efr = value & TWI_EFR_MASK; | |
395 | break; | |
396 | case TWI_LCR_REG: | |
397 | s->lcr = value & TWI_LCR_MASK; | |
398 | break; | |
399 | default: | |
400 | qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" | |
401 | HWADDR_PRIx "\n", TYPE_AW_I2C, __func__, offset); | |
402 | break; | |
403 | } | |
404 | } | |
405 | ||
406 | static const MemoryRegionOps allwinner_i2c_ops = { | |
407 | .read = allwinner_i2c_read, | |
408 | .write = allwinner_i2c_write, | |
409 | .valid.min_access_size = 1, | |
410 | .valid.max_access_size = 4, | |
411 | .endianness = DEVICE_NATIVE_ENDIAN, | |
412 | }; | |
413 | ||
414 | static const VMStateDescription allwinner_i2c_vmstate = { | |
415 | .name = TYPE_AW_I2C, | |
416 | .version_id = 1, | |
417 | .minimum_version_id = 1, | |
418 | .fields = (VMStateField[]) { | |
419 | VMSTATE_UINT8(addr, AWI2CState), | |
420 | VMSTATE_UINT8(xaddr, AWI2CState), | |
421 | VMSTATE_UINT8(data, AWI2CState), | |
422 | VMSTATE_UINT8(cntr, AWI2CState), | |
423 | VMSTATE_UINT8(ccr, AWI2CState), | |
424 | VMSTATE_UINT8(srst, AWI2CState), | |
425 | VMSTATE_UINT8(efr, AWI2CState), | |
426 | VMSTATE_UINT8(lcr, AWI2CState), | |
427 | VMSTATE_END_OF_LIST() | |
428 | } | |
429 | }; | |
430 | ||
431 | static void allwinner_i2c_realize(DeviceState *dev, Error **errp) | |
432 | { | |
433 | AWI2CState *s = AW_I2C(dev); | |
434 | ||
435 | memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_i2c_ops, s, | |
436 | TYPE_AW_I2C, AW_I2C_MEM_SIZE); | |
437 | sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); | |
438 | sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); | |
439 | s->bus = i2c_init_bus(dev, "i2c"); | |
440 | } | |
441 | ||
442 | static void allwinner_i2c_class_init(ObjectClass *klass, void *data) | |
443 | { | |
444 | DeviceClass *dc = DEVICE_CLASS(klass); | |
445 | ResettableClass *rc = RESETTABLE_CLASS(klass); | |
446 | ||
447 | rc->phases.hold = allwinner_i2c_reset_hold; | |
448 | dc->vmsd = &allwinner_i2c_vmstate; | |
449 | dc->realize = allwinner_i2c_realize; | |
450 | dc->desc = "Allwinner I2C Controller"; | |
451 | } | |
452 | ||
453 | static const TypeInfo allwinner_i2c_type_info = { | |
454 | .name = TYPE_AW_I2C, | |
455 | .parent = TYPE_SYS_BUS_DEVICE, | |
456 | .instance_size = sizeof(AWI2CState), | |
457 | .class_init = allwinner_i2c_class_init, | |
458 | }; | |
459 | ||
8461bfdc Z |
460 | static void allwinner_i2c_sun6i_init(Object *obj) |
461 | { | |
462 | AWI2CState *s = AW_I2C(obj); | |
463 | ||
464 | s->irq_clear_inverted = true; | |
465 | } | |
466 | ||
467 | static const TypeInfo allwinner_i2c_sun6i_type_info = { | |
468 | .name = TYPE_AW_I2C_SUN6I, | |
469 | .parent = TYPE_SYS_BUS_DEVICE, | |
470 | .instance_size = sizeof(AWI2CState), | |
471 | .instance_init = allwinner_i2c_sun6i_init, | |
472 | .class_init = allwinner_i2c_class_init, | |
473 | }; | |
474 | ||
9be8a82c SJ |
475 | static void allwinner_i2c_register_types(void) |
476 | { | |
477 | type_register_static(&allwinner_i2c_type_info); | |
8461bfdc | 478 | type_register_static(&allwinner_i2c_sun6i_type_info); |
9be8a82c SJ |
479 | } |
480 | ||
481 | type_init(allwinner_i2c_register_types) |