microblaze: linux-user support.
[qemu] / hw / omap_i2c.c
1 /*
2  * TI OMAP on-chip I2C controller.  Only "new I2C" mode supported.
3  *
4  * Copyright (C) 2007 Andrzej Zaborowski  <balrog@zabor.org>
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 as
8  * published by the Free Software Foundation; either version 2 of
9  * 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 along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 #include "hw.h"
21 #include "i2c.h"
22 #include "omap.h"
23
24 struct omap_i2c_s {
25     qemu_irq irq;
26     qemu_irq drq[2];
27     i2c_bus *bus;
28
29     uint8_t revision;
30     uint8_t mask;
31     uint16_t stat;
32     uint16_t dma;
33     uint16_t count;
34     int count_cur;
35     uint32_t fifo;
36     int rxlen;
37     int txlen;
38     uint16_t control;
39     uint16_t addr[2];
40     uint8_t divider;
41     uint8_t times[2];
42     uint16_t test;
43 };
44
45 #define OMAP2_INTR_REV  0x34
46 #define OMAP2_GC_REV    0x34
47
48 static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
49 {
50     qemu_set_irq(s->irq, s->stat & s->mask);
51     if ((s->dma >> 15) & 1)                                     /* RDMA_EN */
52         qemu_set_irq(s->drq[0], (s->stat >> 3) & 1);            /* RRDY */
53     if ((s->dma >> 7) & 1)                                      /* XDMA_EN */
54         qemu_set_irq(s->drq[1], (s->stat >> 4) & 1);            /* XRDY */
55 }
56
57 static void omap_i2c_fifo_run(struct omap_i2c_s *s)
58 {
59     int ack = 1;
60
61     if (!i2c_bus_busy(s->bus))
62         return;
63
64     if ((s->control >> 2) & 1) {                                /* RM */
65         if ((s->control >> 1) & 1) {                            /* STP */
66             i2c_end_transfer(s->bus);
67             s->control &= ~(1 << 1);                            /* STP */
68             s->count_cur = s->count;
69             s->txlen = 0;
70         } else if ((s->control >> 9) & 1) {                     /* TRX */
71             while (ack && s->txlen)
72                 ack = (i2c_send(s->bus,
73                                         (s->fifo >> ((-- s->txlen) << 3)) &
74                                         0xff) >= 0);
75             s->stat |= 1 << 4;                                  /* XRDY */
76         } else {
77             while (s->rxlen < 4)
78                 s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
79             s->stat |= 1 << 3;                                  /* RRDY */
80         }
81     } else {
82         if ((s->control >> 9) & 1) {                            /* TRX */
83             while (ack && s->count_cur && s->txlen) {
84                 ack = (i2c_send(s->bus,
85                                         (s->fifo >> ((-- s->txlen) << 3)) &
86                                         0xff) >= 0);
87                 s->count_cur --;
88             }
89             if (ack && s->count_cur)
90                 s->stat |= 1 << 4;                              /* XRDY */
91             else
92                 s->stat &= ~(1 << 4);                           /* XRDY */
93             if (!s->count_cur) {
94                 s->stat |= 1 << 2;                              /* ARDY */
95                 s->control &= ~(1 << 10);                       /* MST */
96             }
97         } else {
98             while (s->count_cur && s->rxlen < 4) {
99                 s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
100                 s->count_cur --;
101             }
102             if (s->rxlen)
103                 s->stat |= 1 << 3;                              /* RRDY */
104             else
105                 s->stat &= ~(1 << 3);                           /* RRDY */
106         }
107         if (!s->count_cur) {
108             if ((s->control >> 1) & 1) {                        /* STP */
109                 i2c_end_transfer(s->bus);
110                 s->control &= ~(1 << 1);                        /* STP */
111                 s->count_cur = s->count;
112                 s->txlen = 0;
113             } else {
114                 s->stat |= 1 << 2;                              /* ARDY */
115                 s->control &= ~(1 << 10);                       /* MST */
116             }
117         }
118     }
119
120     s->stat |= (!ack) << 1;                                     /* NACK */
121     if (!ack)
122         s->control &= ~(1 << 1);                                /* STP */
123 }
124
125 void omap_i2c_reset(struct omap_i2c_s *s)
126 {
127     s->mask = 0;
128     s->stat = 0;
129     s->dma = 0;
130     s->count = 0;
131     s->count_cur = 0;
132     s->fifo = 0;
133     s->rxlen = 0;
134     s->txlen = 0;
135     s->control = 0;
136     s->addr[0] = 0;
137     s->addr[1] = 0;
138     s->divider = 0;
139     s->times[0] = 0;
140     s->times[1] = 0;
141     s->test = 0;
142 }
143
144 static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
145 {
146     struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
147     int offset = addr & OMAP_MPUI_REG_MASK;
148     uint16_t ret;
149
150     switch (offset) {
151     case 0x00:  /* I2C_REV */
152         return s->revision;                                     /* REV */
153
154     case 0x04:  /* I2C_IE */
155         return s->mask;
156
157     case 0x08:  /* I2C_STAT */
158         return s->stat | (i2c_bus_busy(s->bus) << 12);
159
160     case 0x0c:  /* I2C_IV */
161         if (s->revision >= OMAP2_INTR_REV)
162             break;
163         ret = ffs(s->stat & s->mask);
164         if (ret)
165             s->stat ^= 1 << (ret - 1);
166         omap_i2c_interrupts_update(s);
167         return ret;
168
169     case 0x10:  /* I2C_SYSS */
170         return (s->control >> 15) & 1;                          /* I2C_EN */
171
172     case 0x14:  /* I2C_BUF */
173         return s->dma;
174
175     case 0x18:  /* I2C_CNT */
176         return s->count_cur;                                    /* DCOUNT */
177
178     case 0x1c:  /* I2C_DATA */
179         ret = 0;
180         if (s->control & (1 << 14)) {                           /* BE */
181             ret |= ((s->fifo >> 0) & 0xff) << 8;
182             ret |= ((s->fifo >> 8) & 0xff) << 0;
183         } else {
184             ret |= ((s->fifo >> 8) & 0xff) << 8;
185             ret |= ((s->fifo >> 0) & 0xff) << 0;
186         }
187         if (s->rxlen == 1) {
188             s->stat |= 1 << 15;                                 /* SBD */
189             s->rxlen = 0;
190         } else if (s->rxlen > 1) {
191             if (s->rxlen > 2)
192                 s->fifo >>= 16;
193             s->rxlen -= 2;
194         } else
195             /* XXX: remote access (qualifier) error - what's that?  */;
196         if (!s->rxlen) {
197             s->stat &= ~(1 << 3);                               /* RRDY */
198             if (((s->control >> 10) & 1) &&                     /* MST */
199                             ((~s->control >> 9) & 1)) {         /* TRX */
200                 s->stat |= 1 << 2;                              /* ARDY */
201                 s->control &= ~(1 << 10);                       /* MST */
202             }
203         }
204         s->stat &= ~(1 << 11);                                  /* ROVR */
205         omap_i2c_fifo_run(s);
206         omap_i2c_interrupts_update(s);
207         return ret;
208
209     case 0x20:  /* I2C_SYSC */
210         return 0;
211
212     case 0x24:  /* I2C_CON */
213         return s->control;
214
215     case 0x28:  /* I2C_OA */
216         return s->addr[0];
217
218     case 0x2c:  /* I2C_SA */
219         return s->addr[1];
220
221     case 0x30:  /* I2C_PSC */
222         return s->divider;
223
224     case 0x34:  /* I2C_SCLL */
225         return s->times[0];
226
227     case 0x38:  /* I2C_SCLH */
228         return s->times[1];
229
230     case 0x3c:  /* I2C_SYSTEST */
231         if (s->test & (1 << 15)) {                              /* ST_EN */
232             s->test ^= 0xa;
233             return s->test;
234         } else
235             return s->test & ~0x300f;
236     }
237
238     OMAP_BAD_REG(addr);
239     return 0;
240 }
241
242 static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
243                 uint32_t value)
244 {
245     struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
246     int offset = addr & OMAP_MPUI_REG_MASK;
247     int nack;
248
249     switch (offset) {
250     case 0x00:  /* I2C_REV */
251     case 0x0c:  /* I2C_IV */
252     case 0x10:  /* I2C_SYSS */
253         OMAP_RO_REG(addr);
254         return;
255
256     case 0x04:  /* I2C_IE */
257         s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
258         break;
259
260     case 0x08:  /* I2C_STAT */
261         if (s->revision < OMAP2_INTR_REV) {
262             OMAP_RO_REG(addr);
263             return;
264         }
265
266         /* RRDY and XRDY are reset by hardware. (in all versions???) */
267         s->stat &= ~(value & 0x27);
268         omap_i2c_interrupts_update(s);
269         break;
270
271     case 0x14:  /* I2C_BUF */
272         s->dma = value & 0x8080;
273         if (value & (1 << 15))                                  /* RDMA_EN */
274             s->mask &= ~(1 << 3);                               /* RRDY_IE */
275         if (value & (1 << 7))                                   /* XDMA_EN */
276             s->mask &= ~(1 << 4);                               /* XRDY_IE */
277         break;
278
279     case 0x18:  /* I2C_CNT */
280         s->count = value;                                       /* DCOUNT */
281         break;
282
283     case 0x1c:  /* I2C_DATA */
284         if (s->txlen > 2) {
285             /* XXX: remote access (qualifier) error - what's that?  */
286             break;
287         }
288         s->fifo <<= 16;
289         s->txlen += 2;
290         if (s->control & (1 << 14)) {                           /* BE */
291             s->fifo |= ((value >> 8) & 0xff) << 8;
292             s->fifo |= ((value >> 0) & 0xff) << 0;
293         } else {
294             s->fifo |= ((value >> 0) & 0xff) << 8;
295             s->fifo |= ((value >> 8) & 0xff) << 0;
296         }
297         s->stat &= ~(1 << 10);                                  /* XUDF */
298         if (s->txlen > 2)
299             s->stat &= ~(1 << 4);                               /* XRDY */
300         omap_i2c_fifo_run(s);
301         omap_i2c_interrupts_update(s);
302         break;
303
304     case 0x20:  /* I2C_SYSC */
305         if (s->revision < OMAP2_INTR_REV) {
306             OMAP_BAD_REG(addr);
307             return;
308         }
309
310         if (value & 2)
311             omap_i2c_reset(s);
312         break;
313
314     case 0x24:  /* I2C_CON */
315         s->control = value & 0xcf87;
316         if (~value & (1 << 15)) {                               /* I2C_EN */
317             if (s->revision < OMAP2_INTR_REV)
318                 omap_i2c_reset(s);
319             break;
320         }
321         if ((value & (1 << 15)) && !(value & (1 << 10))) {      /* MST */
322             fprintf(stderr, "%s: I^2C slave mode not supported\n",
323                             __FUNCTION__);
324             break;
325         }
326         if ((value & (1 << 15)) && value & (1 << 8)) {          /* XA */
327             fprintf(stderr, "%s: 10-bit addressing mode not supported\n",
328                             __FUNCTION__);
329             break;
330         }
331         if ((value & (1 << 15)) && value & (1 << 0)) {          /* STT */
332             nack = !!i2c_start_transfer(s->bus, s->addr[1],     /* SA */
333                             (~value >> 9) & 1);                 /* TRX */
334             s->stat |= nack << 1;                               /* NACK */
335             s->control &= ~(1 << 0);                            /* STT */
336             s->fifo = 0;
337             if (nack)
338                 s->control &= ~(1 << 1);                        /* STP */
339             else {
340                 s->count_cur = s->count;
341                 omap_i2c_fifo_run(s);
342             }
343             omap_i2c_interrupts_update(s);
344         }
345         break;
346
347     case 0x28:  /* I2C_OA */
348         s->addr[0] = value & 0x3ff;
349         break;
350
351     case 0x2c:  /* I2C_SA */
352         s->addr[1] = value & 0x3ff;
353         break;
354
355     case 0x30:  /* I2C_PSC */
356         s->divider = value;
357         break;
358
359     case 0x34:  /* I2C_SCLL */
360         s->times[0] = value;
361         break;
362
363     case 0x38:  /* I2C_SCLH */
364         s->times[1] = value;
365         break;
366
367     case 0x3c:  /* I2C_SYSTEST */
368         s->test = value & 0xf80f;
369         if (value & (1 << 11))                                  /* SBB */
370             if (s->revision >= OMAP2_INTR_REV) {
371                 s->stat |= 0x3f;
372                 omap_i2c_interrupts_update(s);
373             }
374         if (value & (1 << 15))                                  /* ST_EN */
375             fprintf(stderr, "%s: System Test not supported\n", __FUNCTION__);
376         break;
377
378     default:
379         OMAP_BAD_REG(addr);
380         return;
381     }
382 }
383
384 static void omap_i2c_writeb(void *opaque, target_phys_addr_t addr,
385                 uint32_t value)
386 {
387     struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
388     int offset = addr & OMAP_MPUI_REG_MASK;
389
390     switch (offset) {
391     case 0x1c:  /* I2C_DATA */
392         if (s->txlen > 2) {
393             /* XXX: remote access (qualifier) error - what's that?  */
394             break;
395         }
396         s->fifo <<= 8;
397         s->txlen += 1;
398         s->fifo |= value & 0xff;
399         s->stat &= ~(1 << 10);                                  /* XUDF */
400         if (s->txlen > 2)
401             s->stat &= ~(1 << 4);                               /* XRDY */
402         omap_i2c_fifo_run(s);
403         omap_i2c_interrupts_update(s);
404         break;
405
406     default:
407         OMAP_BAD_REG(addr);
408         return;
409     }
410 }
411
412 static CPUReadMemoryFunc *omap_i2c_readfn[] = {
413     omap_badwidth_read16,
414     omap_i2c_read,
415     omap_badwidth_read16,
416 };
417
418 static CPUWriteMemoryFunc *omap_i2c_writefn[] = {
419     omap_i2c_writeb,    /* Only the last fifo write can be 8 bit.  */
420     omap_i2c_write,
421     omap_badwidth_write16,
422 };
423
424 struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
425                 qemu_irq irq, qemu_irq *dma, omap_clk clk)
426 {
427     int iomemtype;
428     struct omap_i2c_s *s = (struct omap_i2c_s *)
429             qemu_mallocz(sizeof(struct omap_i2c_s));
430
431     /* TODO: set a value greater or equal to real hardware */
432     s->revision = 0x11;
433     s->irq = irq;
434     s->drq[0] = dma[0];
435     s->drq[1] = dma[1];
436     s->bus = i2c_init_bus(NULL, "i2c");
437     omap_i2c_reset(s);
438
439     iomemtype = cpu_register_io_memory(0, omap_i2c_readfn,
440                     omap_i2c_writefn, s);
441     cpu_register_physical_memory(base, 0x800, iomemtype);
442
443     return s;
444 }
445
446 struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta,
447                 qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk)
448 {
449     int iomemtype;
450     struct omap_i2c_s *s = (struct omap_i2c_s *)
451             qemu_mallocz(sizeof(struct omap_i2c_s));
452
453     s->revision = 0x34;
454     s->irq = irq;
455     s->drq[0] = dma[0];
456     s->drq[1] = dma[1];
457     s->bus = i2c_init_bus(NULL, "i2c");
458     omap_i2c_reset(s);
459
460     iomemtype = l4_register_io_memory(0, omap_i2c_readfn,
461                     omap_i2c_writefn, s);
462     omap_l4_attach(ta, 0, iomemtype);
463
464     return s;
465 }
466
467 i2c_bus *omap_i2c_bus(struct omap_i2c_s *s)
468 {
469     return s->bus;
470 }