]> Git Repo - qemu.git/blob - hw/omap_i2c.c
Merge remote-tracking branch 'awilliam/ipxe' into staging
[qemu.git] / hw / omap_i2c.c
1 /*
2  * TI OMAP on-chip I2C controller.  Only "new I2C" mode supported.
3  *
4  * Copyright (C) 2007 Andrzej Zaborowski  <[email protected]>
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, see <http://www.gnu.org/licenses/>.
18  */
19 #include "hw.h"
20 #include "i2c.h"
21 #include "omap.h"
22
23 struct omap_i2c_s {
24     qemu_irq irq;
25     qemu_irq drq[2];
26     i2c_bus *bus;
27
28     uint8_t revision;
29     uint8_t mask;
30     uint16_t stat;
31     uint16_t dma;
32     uint16_t count;
33     int count_cur;
34     uint32_t fifo;
35     int rxlen;
36     int txlen;
37     uint16_t control;
38     uint16_t addr[2];
39     uint8_t divider;
40     uint8_t times[2];
41     uint16_t test;
42 };
43
44 #define OMAP2_INTR_REV  0x34
45 #define OMAP2_GC_REV    0x34
46
47 static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
48 {
49     qemu_set_irq(s->irq, s->stat & s->mask);
50     if ((s->dma >> 15) & 1)                                     /* RDMA_EN */
51         qemu_set_irq(s->drq[0], (s->stat >> 3) & 1);            /* RRDY */
52     if ((s->dma >> 7) & 1)                                      /* XDMA_EN */
53         qemu_set_irq(s->drq[1], (s->stat >> 4) & 1);            /* XRDY */
54 }
55
56 static void omap_i2c_fifo_run(struct omap_i2c_s *s)
57 {
58     int ack = 1;
59
60     if (!i2c_bus_busy(s->bus))
61         return;
62
63     if ((s->control >> 2) & 1) {                                /* RM */
64         if ((s->control >> 1) & 1) {                            /* STP */
65             i2c_end_transfer(s->bus);
66             s->control &= ~(1 << 1);                            /* STP */
67             s->count_cur = s->count;
68             s->txlen = 0;
69         } else if ((s->control >> 9) & 1) {                     /* TRX */
70             while (ack && s->txlen)
71                 ack = (i2c_send(s->bus,
72                                         (s->fifo >> ((-- s->txlen) << 3)) &
73                                         0xff) >= 0);
74             s->stat |= 1 << 4;                                  /* XRDY */
75         } else {
76             while (s->rxlen < 4)
77                 s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
78             s->stat |= 1 << 3;                                  /* RRDY */
79         }
80     } else {
81         if ((s->control >> 9) & 1) {                            /* TRX */
82             while (ack && s->count_cur && s->txlen) {
83                 ack = (i2c_send(s->bus,
84                                         (s->fifo >> ((-- s->txlen) << 3)) &
85                                         0xff) >= 0);
86                 s->count_cur --;
87             }
88             if (ack && s->count_cur)
89                 s->stat |= 1 << 4;                              /* XRDY */
90             else
91                 s->stat &= ~(1 << 4);                           /* XRDY */
92             if (!s->count_cur) {
93                 s->stat |= 1 << 2;                              /* ARDY */
94                 s->control &= ~(1 << 10);                       /* MST */
95             }
96         } else {
97             while (s->count_cur && s->rxlen < 4) {
98                 s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
99                 s->count_cur --;
100             }
101             if (s->rxlen)
102                 s->stat |= 1 << 3;                              /* RRDY */
103             else
104                 s->stat &= ~(1 << 3);                           /* RRDY */
105         }
106         if (!s->count_cur) {
107             if ((s->control >> 1) & 1) {                        /* STP */
108                 i2c_end_transfer(s->bus);
109                 s->control &= ~(1 << 1);                        /* STP */
110                 s->count_cur = s->count;
111                 s->txlen = 0;
112             } else {
113                 s->stat |= 1 << 2;                              /* ARDY */
114                 s->control &= ~(1 << 10);                       /* MST */
115             }
116         }
117     }
118
119     s->stat |= (!ack) << 1;                                     /* NACK */
120     if (!ack)
121         s->control &= ~(1 << 1);                                /* STP */
122 }
123
124 void omap_i2c_reset(struct omap_i2c_s *s)
125 {
126     s->mask = 0;
127     s->stat = 0;
128     s->dma = 0;
129     s->count = 0;
130     s->count_cur = 0;
131     s->fifo = 0;
132     s->rxlen = 0;
133     s->txlen = 0;
134     s->control = 0;
135     s->addr[0] = 0;
136     s->addr[1] = 0;
137     s->divider = 0;
138     s->times[0] = 0;
139     s->times[1] = 0;
140     s->test = 0;
141 }
142
143 static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
144 {
145     struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
146     int offset = addr & OMAP_MPUI_REG_MASK;
147     uint16_t ret;
148
149     switch (offset) {
150     case 0x00:  /* I2C_REV */
151         return s->revision;                                     /* REV */
152
153     case 0x04:  /* I2C_IE */
154         return s->mask;
155
156     case 0x08:  /* I2C_STAT */
157         return s->stat | (i2c_bus_busy(s->bus) << 12);
158
159     case 0x0c:  /* I2C_IV */
160         if (s->revision >= OMAP2_INTR_REV)
161             break;
162         ret = ffs(s->stat & s->mask);
163         if (ret)
164             s->stat ^= 1 << (ret - 1);
165         omap_i2c_interrupts_update(s);
166         return ret;
167
168     case 0x10:  /* I2C_SYSS */
169         return (s->control >> 15) & 1;                          /* I2C_EN */
170
171     case 0x14:  /* I2C_BUF */
172         return s->dma;
173
174     case 0x18:  /* I2C_CNT */
175         return s->count_cur;                                    /* DCOUNT */
176
177     case 0x1c:  /* I2C_DATA */
178         ret = 0;
179         if (s->control & (1 << 14)) {                           /* BE */
180             ret |= ((s->fifo >> 0) & 0xff) << 8;
181             ret |= ((s->fifo >> 8) & 0xff) << 0;
182         } else {
183             ret |= ((s->fifo >> 8) & 0xff) << 8;
184             ret |= ((s->fifo >> 0) & 0xff) << 0;
185         }
186         if (s->rxlen == 1) {
187             s->stat |= 1 << 15;                                 /* SBD */
188             s->rxlen = 0;
189         } else if (s->rxlen > 1) {
190             if (s->rxlen > 2)
191                 s->fifo >>= 16;
192             s->rxlen -= 2;
193         } else {
194             /* XXX: remote access (qualifier) error - what's that?  */
195         }
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 * const omap_i2c_readfn[] = {
413     omap_badwidth_read16,
414     omap_i2c_read,
415     omap_badwidth_read16,
416 };
417
418 static CPUWriteMemoryFunc * const 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(omap_i2c_readfn,
440                     omap_i2c_writefn, s, DEVICE_NATIVE_ENDIAN);
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(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 }
This page took 0.052175 seconds and 4 git commands to generate.