1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include "qemu/osdep.h"
20#include "hw/hw.h"
21#include "hw/i2c/i2c.h"
22#include "hw/arm/omap.h"
23#include "hw/sysbus.h"
24#include "qemu/error-report.h"
25#include "qapi/error.h"
26
27#define TYPE_OMAP_I2C "omap_i2c"
28#define OMAP_I2C(obj) OBJECT_CHECK(OMAPI2CState, (obj), TYPE_OMAP_I2C)
29
30typedef struct OMAPI2CState {
31 SysBusDevice parent_obj;
32
33 MemoryRegion iomem;
34 qemu_irq irq;
35 qemu_irq drq[2];
36 I2CBus *bus;
37
38 uint8_t revision;
39 void *iclk;
40 void *fclk;
41
42 uint8_t mask;
43 uint16_t stat;
44 uint16_t dma;
45 uint16_t count;
46 int count_cur;
47 uint32_t fifo;
48 int rxlen;
49 int txlen;
50 uint16_t control;
51 uint16_t addr[2];
52 uint8_t divider;
53 uint8_t times[2];
54 uint16_t test;
55} OMAPI2CState;
56
57#define OMAP2_INTR_REV 0x34
58#define OMAP2_GC_REV 0x34
59
60static void omap_i2c_interrupts_update(OMAPI2CState *s)
61{
62 qemu_set_irq(s->irq, s->stat & s->mask);
63 if ((s->dma >> 15) & 1)
64 qemu_set_irq(s->drq[0], (s->stat >> 3) & 1);
65 if ((s->dma >> 7) & 1)
66 qemu_set_irq(s->drq[1], (s->stat >> 4) & 1);
67}
68
69static void omap_i2c_fifo_run(OMAPI2CState *s)
70{
71 int ack = 1;
72
73 if (!i2c_bus_busy(s->bus))
74 return;
75
76 if ((s->control >> 2) & 1) {
77 if ((s->control >> 1) & 1) {
78 i2c_end_transfer(s->bus);
79 s->control &= ~(1 << 1);
80 s->count_cur = s->count;
81 s->txlen = 0;
82 } else if ((s->control >> 9) & 1) {
83 while (ack && s->txlen)
84 ack = (i2c_send(s->bus,
85 (s->fifo >> ((-- s->txlen) << 3)) &
86 0xff) >= 0);
87 s->stat |= 1 << 4;
88 } else {
89 while (s->rxlen < 4)
90 s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
91 s->stat |= 1 << 3;
92 }
93 } else {
94 if ((s->control >> 9) & 1) {
95 while (ack && s->count_cur && s->txlen) {
96 ack = (i2c_send(s->bus,
97 (s->fifo >> ((-- s->txlen) << 3)) &
98 0xff) >= 0);
99 s->count_cur --;
100 }
101 if (ack && s->count_cur)
102 s->stat |= 1 << 4;
103 else
104 s->stat &= ~(1 << 4);
105 if (!s->count_cur) {
106 s->stat |= 1 << 2;
107 s->control &= ~(1 << 10);
108 }
109 } else {
110 while (s->count_cur && s->rxlen < 4) {
111 s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
112 s->count_cur --;
113 }
114 if (s->rxlen)
115 s->stat |= 1 << 3;
116 else
117 s->stat &= ~(1 << 3);
118 }
119 if (!s->count_cur) {
120 if ((s->control >> 1) & 1) {
121 i2c_end_transfer(s->bus);
122 s->control &= ~(1 << 1);
123 s->count_cur = s->count;
124 s->txlen = 0;
125 } else {
126 s->stat |= 1 << 2;
127 s->control &= ~(1 << 10);
128 }
129 }
130 }
131
132 s->stat |= (!ack) << 1;
133 if (!ack)
134 s->control &= ~(1 << 1);
135}
136
137static void omap_i2c_reset(DeviceState *dev)
138{
139 OMAPI2CState *s = OMAP_I2C(dev);
140
141 s->mask = 0;
142 s->stat = 0;
143 s->dma = 0;
144 s->count = 0;
145 s->count_cur = 0;
146 s->fifo = 0;
147 s->rxlen = 0;
148 s->txlen = 0;
149 s->control = 0;
150 s->addr[0] = 0;
151 s->addr[1] = 0;
152 s->divider = 0;
153 s->times[0] = 0;
154 s->times[1] = 0;
155 s->test = 0;
156}
157
158static uint32_t omap_i2c_read(void *opaque, hwaddr addr)
159{
160 OMAPI2CState *s = opaque;
161 int offset = addr & OMAP_MPUI_REG_MASK;
162 uint16_t ret;
163
164 switch (offset) {
165 case 0x00:
166 return s->revision;
167
168 case 0x04:
169 return s->mask;
170
171 case 0x08:
172 return s->stat | (i2c_bus_busy(s->bus) << 12);
173
174 case 0x0c:
175 if (s->revision >= OMAP2_INTR_REV)
176 break;
177 ret = ctz32(s->stat & s->mask);
178 if (ret != 32) {
179 s->stat ^= 1 << ret;
180 ret++;
181 } else {
182 ret = 0;
183 }
184 omap_i2c_interrupts_update(s);
185 return ret;
186
187 case 0x10:
188 return (s->control >> 15) & 1;
189
190 case 0x14:
191 return s->dma;
192
193 case 0x18:
194 return s->count_cur;
195
196 case 0x1c:
197 ret = 0;
198 if (s->control & (1 << 14)) {
199 ret |= ((s->fifo >> 0) & 0xff) << 8;
200 ret |= ((s->fifo >> 8) & 0xff) << 0;
201 } else {
202 ret |= ((s->fifo >> 8) & 0xff) << 8;
203 ret |= ((s->fifo >> 0) & 0xff) << 0;
204 }
205 if (s->rxlen == 1) {
206 s->stat |= 1 << 15;
207 s->rxlen = 0;
208 } else if (s->rxlen > 1) {
209 if (s->rxlen > 2)
210 s->fifo >>= 16;
211 s->rxlen -= 2;
212 } else {
213
214 }
215 if (!s->rxlen) {
216 s->stat &= ~(1 << 3);
217 if (((s->control >> 10) & 1) &&
218 ((~s->control >> 9) & 1)) {
219 s->stat |= 1 << 2;
220 s->control &= ~(1 << 10);
221 }
222 }
223 s->stat &= ~(1 << 11);
224 omap_i2c_fifo_run(s);
225 omap_i2c_interrupts_update(s);
226 return ret;
227
228 case 0x20:
229 return 0;
230
231 case 0x24:
232 return s->control;
233
234 case 0x28:
235 return s->addr[0];
236
237 case 0x2c:
238 return s->addr[1];
239
240 case 0x30:
241 return s->divider;
242
243 case 0x34:
244 return s->times[0];
245
246 case 0x38:
247 return s->times[1];
248
249 case 0x3c:
250 if (s->test & (1 << 15)) {
251 s->test ^= 0xa;
252 return s->test;
253 } else
254 return s->test & ~0x300f;
255 }
256
257 OMAP_BAD_REG(addr);
258 return 0;
259}
260
261static void omap_i2c_write(void *opaque, hwaddr addr,
262 uint32_t value)
263{
264 OMAPI2CState *s = opaque;
265 int offset = addr & OMAP_MPUI_REG_MASK;
266 int nack;
267
268 switch (offset) {
269 case 0x00:
270 case 0x0c:
271 case 0x10:
272 OMAP_RO_REG(addr);
273 return;
274
275 case 0x04:
276 s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
277 break;
278
279 case 0x08:
280 if (s->revision < OMAP2_INTR_REV) {
281 OMAP_RO_REG(addr);
282 return;
283 }
284
285
286 s->stat &= ~(value & 0x27);
287 omap_i2c_interrupts_update(s);
288 break;
289
290 case 0x14:
291 s->dma = value & 0x8080;
292 if (value & (1 << 15))
293 s->mask &= ~(1 << 3);
294 if (value & (1 << 7))
295 s->mask &= ~(1 << 4);
296 break;
297
298 case 0x18:
299 s->count = value;
300 break;
301
302 case 0x1c:
303 if (s->txlen > 2) {
304
305 break;
306 }
307 s->fifo <<= 16;
308 s->txlen += 2;
309 if (s->control & (1 << 14)) {
310 s->fifo |= ((value >> 8) & 0xff) << 8;
311 s->fifo |= ((value >> 0) & 0xff) << 0;
312 } else {
313 s->fifo |= ((value >> 0) & 0xff) << 8;
314 s->fifo |= ((value >> 8) & 0xff) << 0;
315 }
316 s->stat &= ~(1 << 10);
317 if (s->txlen > 2)
318 s->stat &= ~(1 << 4);
319 omap_i2c_fifo_run(s);
320 omap_i2c_interrupts_update(s);
321 break;
322
323 case 0x20:
324 if (s->revision < OMAP2_INTR_REV) {
325 OMAP_BAD_REG(addr);
326 return;
327 }
328
329 if (value & 2) {
330 omap_i2c_reset(DEVICE(s));
331 }
332 break;
333
334 case 0x24:
335 s->control = value & 0xcf87;
336 if (~value & (1 << 15)) {
337 if (s->revision < OMAP2_INTR_REV) {
338 omap_i2c_reset(DEVICE(s));
339 }
340 break;
341 }
342 if ((value & (1 << 15)) && !(value & (1 << 10))) {
343 fprintf(stderr, "%s: I^2C slave mode not supported\n",
344 __FUNCTION__);
345 break;
346 }
347 if ((value & (1 << 15)) && value & (1 << 8)) {
348 fprintf(stderr, "%s: 10-bit addressing mode not supported\n",
349 __FUNCTION__);
350 break;
351 }
352 if ((value & (1 << 15)) && value & (1 << 0)) {
353 nack = !!i2c_start_transfer(s->bus, s->addr[1],
354 (~value >> 9) & 1);
355 s->stat |= nack << 1;
356 s->control &= ~(1 << 0);
357 s->fifo = 0;
358 if (nack)
359 s->control &= ~(1 << 1);
360 else {
361 s->count_cur = s->count;
362 omap_i2c_fifo_run(s);
363 }
364 omap_i2c_interrupts_update(s);
365 }
366 break;
367
368 case 0x28:
369 s->addr[0] = value & 0x3ff;
370 break;
371
372 case 0x2c:
373 s->addr[1] = value & 0x3ff;
374 break;
375
376 case 0x30:
377 s->divider = value;
378 break;
379
380 case 0x34:
381 s->times[0] = value;
382 break;
383
384 case 0x38:
385 s->times[1] = value;
386 break;
387
388 case 0x3c:
389 s->test = value & 0xf80f;
390 if (value & (1 << 11))
391 if (s->revision >= OMAP2_INTR_REV) {
392 s->stat |= 0x3f;
393 omap_i2c_interrupts_update(s);
394 }
395 if (value & (1 << 15))
396 fprintf(stderr, "%s: System Test not supported\n", __FUNCTION__);
397 break;
398
399 default:
400 OMAP_BAD_REG(addr);
401 return;
402 }
403}
404
405static void omap_i2c_writeb(void *opaque, hwaddr addr,
406 uint32_t value)
407{
408 OMAPI2CState *s = opaque;
409 int offset = addr & OMAP_MPUI_REG_MASK;
410
411 switch (offset) {
412 case 0x1c:
413 if (s->txlen > 2) {
414
415 break;
416 }
417 s->fifo <<= 8;
418 s->txlen += 1;
419 s->fifo |= value & 0xff;
420 s->stat &= ~(1 << 10);
421 if (s->txlen > 2)
422 s->stat &= ~(1 << 4);
423 omap_i2c_fifo_run(s);
424 omap_i2c_interrupts_update(s);
425 break;
426
427 default:
428 OMAP_BAD_REG(addr);
429 return;
430 }
431}
432
433static const MemoryRegionOps omap_i2c_ops = {
434 .old_mmio = {
435 .read = {
436 omap_badwidth_read16,
437 omap_i2c_read,
438 omap_badwidth_read16,
439 },
440 .write = {
441 omap_i2c_writeb,
442 omap_i2c_write,
443 omap_badwidth_write16,
444 },
445 },
446 .endianness = DEVICE_NATIVE_ENDIAN,
447};
448
449static void omap_i2c_init(Object *obj)
450{
451 DeviceState *dev = DEVICE(obj);
452 OMAPI2CState *s = OMAP_I2C(obj);
453 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
454
455 sysbus_init_irq(sbd, &s->irq);
456 sysbus_init_irq(sbd, &s->drq[0]);
457 sysbus_init_irq(sbd, &s->drq[1]);
458 sysbus_init_mmio(sbd, &s->iomem);
459 s->bus = i2c_init_bus(dev, NULL);
460}
461
462static void omap_i2c_realize(DeviceState *dev, Error **errp)
463{
464 OMAPI2CState *s = OMAP_I2C(dev);
465
466 memory_region_init_io(&s->iomem, OBJECT(dev), &omap_i2c_ops, s, "omap.i2c",
467 (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000);
468
469 if (!s->fclk) {
470 error_setg(errp, "omap_i2c: fclk not connected");
471 return;
472 }
473 if (s->revision >= OMAP2_INTR_REV && !s->iclk) {
474
475 error_setg(errp, "omap_i2c: iclk not connected");
476 return;
477 }
478}
479
480static Property omap_i2c_properties[] = {
481 DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0),
482 DEFINE_PROP_PTR("iclk", OMAPI2CState, iclk),
483 DEFINE_PROP_PTR("fclk", OMAPI2CState, fclk),
484 DEFINE_PROP_END_OF_LIST(),
485};
486
487static void omap_i2c_class_init(ObjectClass *klass, void *data)
488{
489 DeviceClass *dc = DEVICE_CLASS(klass);
490
491 dc->props = omap_i2c_properties;
492 dc->reset = omap_i2c_reset;
493
494 dc->cannot_instantiate_with_device_add_yet = true;
495 dc->realize = omap_i2c_realize;
496}
497
498static const TypeInfo omap_i2c_info = {
499 .name = TYPE_OMAP_I2C,
500 .parent = TYPE_SYS_BUS_DEVICE,
501 .instance_size = sizeof(OMAPI2CState),
502 .instance_init = omap_i2c_init,
503 .class_init = omap_i2c_class_init,
504};
505
506static void omap_i2c_register_types(void)
507{
508 type_register_static(&omap_i2c_info);
509}
510
511I2CBus *omap_i2c_bus(DeviceState *omap_i2c)
512{
513 OMAPI2CState *s = OMAP_I2C(omap_i2c);
514 return s->bus;
515}
516
517type_init(omap_i2c_register_types)
518