~ubuntu-branches/ubuntu/trusty/qemu/trusty

« back to all changes in this revision

Viewing changes to .pc/linaro/0024-hw-omap_i2c-Treat-32-bit-accesses-like-16-bit-access.patch/hw/i2c/omap_i2c.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2014-02-04 12:13:08 UTC
  • mfrom: (10.1.45 sid)
  • Revision ID: package-import@ubuntu.com-20140204121308-1xq92lrfs75agw2g
Tags: 1.7.0+dfsg-3ubuntu1~ppa1
* Merge 1.7.0+dfsg-3 from debian.  Remaining changes:
  - debian/patches/ubuntu:
    * expose-vmx_qemu64cpu.patch
    * linaro (omap3) and arm64 patches
    * ubuntu/target-ppc-add-stubs-for-kvm-breakpoints: fix FTBFS
      on ppc
    * ubuntu/CVE-2013-4377.patch: fix denial of service via virtio
  - debian/qemu-system-x86.modprobe: set kvm_intel nested=1 options
  - debian/control:
    * add arm64 to Architectures
    * add qemu-common and qemu-system-aarch64 packages
  - debian/qemu-system-common.install: add debian/tmp/usr/lib
  - debian/qemu-system-common.preinst: add kvm group
  - debian/qemu-system-common.postinst: remove acl placed by udev,
    and add udevadm trigger.
  - qemu-system-x86.links: add eepro100.rom, remove pxe-virtio,
    pxe-e1000 and pxe-rtl8139.
  - add qemu-system-x86.qemu-kvm.upstart and .default
  - qemu-user-static.postinst-in: remove arm64 binfmt
  - debian/rules:
    * allow parallel build
    * add aarch64 to system_targets and sys_systems
    * add qemu-kvm-spice links
    * install qemu-system-x86.modprobe
  - add debian/qemu-system-common.links for OVMF.fd link
* Remove kvm-img, kvm-nbd, kvm-ifup and kvm-ifdown symlinks.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * TI OMAP on-chip I2C controller.  Only "new I2C" mode supported.
3
 
 *
4
 
 * Copyright (C) 2007 Andrzej Zaborowski  <balrog@zabor.org>
5
 
 * Copyright (C) 2009 Nokia Corporation
6
 
 *
7
 
 * This program is free software; you can redistribute it and/or
8
 
 * modify it under the terms of the GNU General Public License as
9
 
 * published by the Free Software Foundation; either version 2 of
10
 
 * the License, or (at your option) any later version.
11
 
 *
12
 
 * This program is distributed in the hope that it will be useful,
13
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
 * GNU General Public License for more details.
16
 
 *
17
 
 * You should have received a copy of the GNU General Public License along
18
 
 * with this program; if not, see <http://www.gnu.org/licenses/>.
19
 
 */
20
 
#include "hw/hw.h"
21
 
#include "hw/i2c/i2c.h"
22
 
#include "hw/arm/omap.h"
23
 
#include "hw/sysbus.h"
24
 
 
25
 
#define TYPE_OMAP_I2C "omap_i2c"
26
 
#define OMAP_I2C(obj) OBJECT_CHECK(OMAPI2CState, (obj), TYPE_OMAP_I2C)
27
 
 
28
 
#define I2C_MAX_FIFO_SIZE (1 << 6)
29
 
#define I2C_FIFO_SIZE_MASK ((I2C_MAX_FIFO_SIZE) - 1)
30
 
 
31
 
typedef struct OMAPI2CState {
32
 
    SysBusDevice parent_obj;
33
 
 
34
 
    MemoryRegion iomem;
35
 
    qemu_irq irq;
36
 
    qemu_irq drq[2];
37
 
    i2c_bus *bus;
38
 
 
39
 
    uint8_t revision;
40
 
    uint32_t fifosize;
41
 
    void *iclk;
42
 
    void *fclk;
43
 
 
44
 
    uint16_t mask;
45
 
    uint16_t stat;
46
 
    uint16_t we;
47
 
    uint16_t dma;
48
 
    uint16_t count;
49
 
    int count_cur;
50
 
    uint16_t sysc;
51
 
    uint16_t control;
52
 
    uint16_t own_addr[4];
53
 
    uint16_t slave_addr;
54
 
    uint8_t sblock;
55
 
    uint8_t divider;
56
 
    uint16_t times[2];
57
 
    uint16_t test;
58
 
    int fifostart;
59
 
    int fifolen;
60
 
    uint8_t fifo[I2C_MAX_FIFO_SIZE];
61
 
} OMAPI2CState;
62
 
 
63
 
/* I2C controller revision register values */
64
 
#define OMAP1_INTR_REV    0x11
65
 
#define OMAP2_INTR_REV    0x34
66
 
#define OMAP3_INTR_REV    0x3c
67
 
#define OMAP3630_INTR_REV 0x40
68
 
 
69
 
static void omap_i2c_interrupts_update(OMAPI2CState *s)
70
 
{
71
 
    qemu_set_irq(s->irq, s->stat & s->mask);
72
 
    if ((s->dma >> 15) & 1)                                     /* RDMA_EN */
73
 
        qemu_set_irq(s->drq[0], (s->stat >> 3) & 1);            /* RRDY */
74
 
    if ((s->dma >> 7) & 1)                                      /* XDMA_EN */
75
 
        qemu_set_irq(s->drq[1], (s->stat >> 4) & 1);            /* XRDY */
76
 
}
77
 
 
78
 
static void omap_i2c_fifo_run(OMAPI2CState *s)
79
 
{
80
 
    int ack = 1, i;
81
 
 
82
 
    if (!i2c_bus_busy(s->bus))
83
 
        return;
84
 
 
85
 
    if ((s->control >> 2) & 1) {                                /* RM */
86
 
        if ((s->control >> 1) & 1) {                            /* STP */
87
 
            i2c_end_transfer(s->bus);
88
 
            s->control &= ~(1 << 1);                            /* STP */
89
 
            s->count_cur = s->count;
90
 
            s->fifolen = 0;
91
 
        } else if ((s->control >> 9) & 1) {                     /* TRX */
92
 
            while (ack && s->fifolen) {
93
 
                ack = (i2c_send(s->bus, s->fifo[s->fifostart++]) >= 0);
94
 
                s->fifostart &= I2C_FIFO_SIZE_MASK;
95
 
                s->fifolen--;
96
 
            }
97
 
            s->fifolen = 0;
98
 
            s->stat |= 1 << 4;                                  /* XRDY */
99
 
        } else {
100
 
            for (i = 0; i < 4; i++)
101
 
                s->fifo[(s->fifostart + i) & I2C_FIFO_SIZE_MASK] =
102
 
                    i2c_recv(s->bus);
103
 
            s->fifolen = 4;
104
 
            s->stat |= 1 << 3;                                  /* RRDY */
105
 
        }
106
 
    } else {
107
 
        if ((s->control >> 9) & 1) {                            /* TRX */
108
 
            for (; ack && s->count_cur && s->fifolen; s->count_cur--) {
109
 
                ack = (i2c_send(s->bus, s->fifo[s->fifostart++]) >= 0);
110
 
                s->fifostart &= I2C_FIFO_SIZE_MASK;
111
 
                s->fifolen--;
112
 
            }
113
 
            s->stat &= ~0x4410;                     /* XDR | XUDF | XRDY */
114
 
            if (ack && s->count_cur) {              /* send more? */
115
 
                /* we know that FIFO is empty */
116
 
                if (s->revision < OMAP3_INTR_REV)
117
 
                    s->stat |= 1 << 4;              /* XRDY */
118
 
                else {
119
 
                    if (s->count_cur > (s->dma & 0x3f)) /* XTRSH */
120
 
                s->stat |= 1 << 4;                              /* XRDY */
121
 
            else
122
 
                        s->stat |= 1 << 14;         /* XDR */
123
 
            }
124
 
            }
125
 
            if (!s->count_cur)                      /* everything sent? */
126
 
                s->stat |= 1 << 2;                  /* ARDY */
127
 
        } else {                                    /* !TRX */
128
 
            for (; s->count_cur && s->fifolen < s->fifosize; s->count_cur--) {
129
 
                i = i2c_recv(s->bus);
130
 
                if (i < 0) break; /* stop receiving if nothing to receive */
131
 
                s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
132
 
                    (uint8_t)(i & 0xff);
133
 
            }
134
 
            s->stat &= ~((1 << 3) | (1 << 13));            /* RRDY | RDR */
135
 
            if (s->fifolen) {
136
 
                if (s->revision < OMAP3_INTR_REV)
137
 
                    s->stat |= 1 << 3;                     /* RRDY */
138
 
                else {
139
 
                    if (s->fifolen > ((s->dma >> 8) & 0x3f)) /* RTRSH */
140
 
                s->stat |= 1 << 3;                              /* RRDY */
141
 
            else
142
 
                        s->stat |= 1 << 13;                /* RDR */
143
 
                }
144
 
            } else if (!s->count_cur && (s->control & 2))  /* STP */
145
 
                s->stat |= 1 << 2;                         /* ARDY */
146
 
        }
147
 
        if (!s->count_cur) {
148
 
            i2c_end_transfer(s->bus);
149
 
            if ((s->control >> 1) & 1) {                        /* STP */
150
 
                s->control &= ~0x0602;     /* MST | TRX | STP */
151
 
                s->count_cur = s->count;
152
 
            }
153
 
        }
154
 
    }
155
 
 
156
 
    s->stat |= (!ack) << 1;                                     /* NACK */
157
 
    if (!ack)
158
 
        s->control &= ~(1 << 1);                                /* STP */
159
 
}
160
 
 
161
 
static void omap_i2c_reset(DeviceState *dev)
162
 
{
163
 
    OMAPI2CState *s = OMAP_I2C(dev);
164
 
 
165
 
    s->mask = 0;
166
 
    s->stat = 0;
167
 
    s->dma = 0;
168
 
    s->count = 0;
169
 
    s->count_cur = 0;
170
 
    s->we = 0;
171
 
    s->sysc = 0;
172
 
    s->fifolen = 0;
173
 
    s->fifostart = 0;
174
 
    s->control = 0;
175
 
    s->own_addr[0] = 0;
176
 
    s->own_addr[1] = 0;
177
 
    s->own_addr[2] = 0;
178
 
    s->own_addr[3] = 0;
179
 
    s->slave_addr = 0;
180
 
    s->sblock = 0;
181
 
    s->divider = 0;
182
 
    s->times[0] = 0;
183
 
    s->times[1] = 0;
184
 
    s->test = 0;
185
 
    
186
 
    i2c_end_transfer(s->bus);
187
 
}
188
 
 
189
 
static uint32_t omap_i2c_read(void *opaque, hwaddr addr)
190
 
{
191
 
    OMAPI2CState *s = opaque;
192
 
    int offset = addr & OMAP_MPUI_REG_MASK;
193
 
    uint16_t ret;
194
 
 
195
 
    switch (offset) {
196
 
    case 0x00:  /* I2C_REV */
197
 
        return s->revision;                                     /* REV */
198
 
 
199
 
    case 0x04:  /* I2C_IE */
200
 
        return s->mask;
201
 
 
202
 
    case 0x08:  /* I2C_STAT */
203
 
        ret = s->stat | (i2c_bus_busy(s->bus) << 12 );
204
 
        if (s->revision >= OMAP3_INTR_REV && (s->stat & 0x4010)) /* XRDY or XDR  */
205
 
            s->stat |= 1 << 10; /* XUDF as required by errata 1.153 */
206
 
        return ret;
207
 
 
208
 
    case 0x0c: /* I2C_IV / I2C_WE */
209
 
        if (s->revision >= OMAP3_INTR_REV)
210
 
            return s->we;
211
 
        if (s->revision >= OMAP2_INTR_REV)
212
 
            break;
213
 
        ret = ffs(s->stat & s->mask);
214
 
        if (ret)
215
 
            s->stat ^= 1 << (ret - 1);
216
 
        omap_i2c_interrupts_update(s);
217
 
        return ret;
218
 
 
219
 
    case 0x10:  /* I2C_SYSS */
220
 
        return (s->control >> 15) & 1;                          /* I2C_EN */
221
 
 
222
 
    case 0x14:  /* I2C_BUF */
223
 
        return s->dma;
224
 
 
225
 
    case 0x18:  /* I2C_CNT */
226
 
        return s->count_cur;                                    /* DCOUNT */
227
 
 
228
 
    case 0x1c:  /* I2C_DATA */
229
 
        ret = 0;
230
 
        if (s->fifolen) {
231
 
            if (s->revision < OMAP3_INTR_REV) {
232
 
                if (s->control & (1 << 14)) /* BE */
233
 
                    ret = (((uint16_t)s->fifo[s->fifostart]) << 8) 
234
 
                        | s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK];
235
 
                else
236
 
                    ret = (((uint16_t)s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK]) << 8) 
237
 
                        | s->fifo[s->fifostart];
238
 
                s->fifostart = (s->fifostart + 2) & I2C_FIFO_SIZE_MASK;
239
 
                if (s->fifolen == 1) {
240
 
                    s->stat |= 1 << 15;                                 /* SBD */
241
 
                    s->fifolen = 0;
242
 
                } else
243
 
                    s->fifolen -= 2;
244
 
                if (!s->fifolen) {
245
 
                    s->stat &= ~(1 << 3); /* RRDY */
246
 
                    s->stat |= 1 << 2;    /* ARDY */
247
 
                }
248
 
            } else {
249
 
                s->stat &= ~(1 << 7); /* AERR */
250
 
                ret = s->fifo[s->fifostart++];
251
 
                s->fifostart &= I2C_FIFO_SIZE_MASK;
252
 
                if (--s->fifolen) {
253
 
                    if (s->fifolen <= ((s->dma >> 8) & 0x3f)) {
254
 
                        s->stat &= ~(1 << 3);                           /* RRDY */
255
 
                        s->stat |= 1 << 13;   /* RDR */
256
 
                    }
257
 
                } else {
258
 
                    s->stat &= ~((1 << 3) | (1 << 13)); /* RRDY | RDR */
259
 
                    s->stat |= 1 << 2;                          /* ARDY */
260
 
                }
261
 
            }
262
 
            s->stat &= ~(1 << 11);                                      /* ROVR */
263
 
        } else if (s->revision >= OMAP3_INTR_REV)
264
 
            s->stat |= (1 << 7); /* AERR */
265
 
        omap_i2c_fifo_run(s);
266
 
        omap_i2c_interrupts_update(s);
267
 
        return ret;
268
 
 
269
 
    case 0x20:  /* I2C_SYSC */
270
 
        return s->sysc;
271
 
 
272
 
    case 0x24:  /* I2C_CON */
273
 
        return s->control;
274
 
 
275
 
    case 0x28: /* I2C_OA / I2C_OA0 */
276
 
        return s->own_addr[0];
277
 
 
278
 
    case 0x2c:  /* I2C_SA */
279
 
        return s->slave_addr;
280
 
 
281
 
    case 0x30:  /* I2C_PSC */
282
 
        return s->divider;
283
 
 
284
 
    case 0x34:  /* I2C_SCLL */
285
 
        return s->times[0];
286
 
 
287
 
    case 0x38:  /* I2C_SCLH */
288
 
        return s->times[1];
289
 
 
290
 
    case 0x3c:  /* I2C_SYSTEST */
291
 
        if (s->test & (1 << 15)) {                              /* ST_EN */
292
 
            s->test ^= 0xa;
293
 
            return s->test;
294
 
        }
295
 
        return s->test & ~0x300f;
296
 
    case 0x40: /* I2C_BUFSTAT */
297
 
        if (s->revision >= OMAP3_INTR_REV) {
298
 
            switch (s->fifosize) {
299
 
            case 8:  ret = 0x0000; break;
300
 
            case 16: ret = 0x4000; break;
301
 
            case 32: ret = 0x8000; break;
302
 
            case 64: ret = 0xc000; break;
303
 
            default: ret = 0x0000; break;
304
 
            }
305
 
            ret |= ((s->fifolen) & 0x3f) << 8;  /* RXSTAT */
306
 
            ret |= (s->count_cur) & 0x3f;       /* TXSTAT */
307
 
            return ret;
308
 
        }
309
 
        break;
310
 
    case 0x44: /* I2C_OA1 */
311
 
    case 0x48: /* I2C_OA2 */
312
 
    case 0x4c: /* I2C_OA3 */
313
 
        if (s->revision >= OMAP3_INTR_REV)
314
 
            return s->own_addr[(addr >> 2) & 3];
315
 
        break;
316
 
    case 0x50: /* I2C_ACTOA */
317
 
        if (s->revision >= OMAP3_INTR_REV)
318
 
            return 0; /* TODO: determine accessed slave own address */
319
 
        break;
320
 
    case 0x54: /* I2C_SBLOCK */
321
 
        if (s->revision >= OMAP3_INTR_REV)
322
 
            return s->sblock;
323
 
        break;
324
 
    default:
325
 
        break;
326
 
    }
327
 
 
328
 
    OMAP_BAD_REG(addr);
329
 
    return 0;
330
 
}
331
 
 
332
 
static uint32_t omap_i2c_readb(void *opaque, hwaddr addr)
333
 
{
334
 
    OMAPI2CState *s = opaque;
335
 
    int offset = addr & OMAP_MPUI_REG_MASK;
336
 
    uint8_t ret;
337
 
 
338
 
    switch (offset) {
339
 
    case 0x1c: /* I2C_DATA */
340
 
        ret = 0;
341
 
        if (s->fifolen) {
342
 
            if (s->revision < OMAP3_INTR_REV) {
343
 
                if (s->control & (1 << 14)) /* BE */
344
 
                    ret = (((uint8_t)s->fifo[s->fifostart]) << 8)
345
 
                        | s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK];
346
 
                else
347
 
                    ret = (((uint8_t)s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK]) << 8)
348
 
                        | s->fifo[s->fifostart];
349
 
                s->fifostart = (s->fifostart + 2) & I2C_FIFO_SIZE_MASK;
350
 
                if (s->fifolen == 1) {
351
 
                    s->stat |= 1 << 15; /* SBD */
352
 
                    s->fifolen = 0;
353
 
                } else
354
 
                    s->fifolen -= 2;
355
 
                if (!s->fifolen) {
356
 
                    s->stat &= ~(1 << 3); /* RRDY */
357
 
                    s->stat |= 1 << 2;    /* ARDY */
358
 
                }
359
 
            } else {
360
 
                s->stat &= ~(1 << 7); /* AERR */
361
 
                ret = (uint8_t)s->fifo[s->fifostart++];
362
 
                s->fifostart &= I2C_FIFO_SIZE_MASK;
363
 
                if (--s->fifolen) {
364
 
                    if (s->fifolen <= ((s->dma >> 8) & 0x3f)) {
365
 
                        s->stat &= ~(1 << 3); /* RRDY */
366
 
                        s->stat |= 1 << 13;   /* RDR */
367
 
                    }
368
 
                } else {
369
 
                    s->stat &= ~((1 << 3) | (1 << 13)); /* RRDY | RDR */
370
 
                    s->stat |= 1 << 2;                  /* ARDY */
371
 
                }
372
 
            }
373
 
            s->stat &= ~(1 << 11); /* ROVR */
374
 
        } else if (s->revision >= OMAP3_INTR_REV)
375
 
            s->stat |= (1 << 7); /* AERR */
376
 
        omap_i2c_fifo_run(s);
377
 
        omap_i2c_interrupts_update(s);
378
 
        return ret;
379
 
    default:
380
 
        break;
381
 
    }
382
 
 
383
 
    OMAP_BAD_REG(addr);
384
 
    return 0;
385
 
}
386
 
 
387
 
static void omap_i2c_write(void *opaque, hwaddr addr,
388
 
                uint32_t value)
389
 
{
390
 
    OMAPI2CState *s = opaque;
391
 
    int offset = addr & OMAP_MPUI_REG_MASK;
392
 
    int nack;
393
 
 
394
 
    switch (offset) {
395
 
    case 0x00:  /* I2C_REV */
396
 
    case 0x10:  /* I2C_SYSS */
397
 
    case 0x40: /* I2C_BUFSTAT */
398
 
    case 0x50: /* I2C_ACTOA */
399
 
        OMAP_RO_REG(addr);
400
 
        break;
401
 
    case 0x04:  /* I2C_IE */
402
 
        if (s->revision < OMAP2_INTR_REV) {
403
 
            s->mask = value & 0x1f;
404
 
        } else if (s->revision < OMAP3_INTR_REV) {
405
 
            s->mask = value & 0x3f;
406
 
        } else if (s->revision == OMAP3_INTR_REV) {
407
 
            s->mask = value & 0x63ff;
408
 
        } else { /* omap3630 */
409
 
            s->mask = value & 0x6fff;
410
 
        }
411
 
        omap_i2c_interrupts_update(s);
412
 
        break;
413
 
    case 0x08:  /* I2C_STAT */
414
 
        if (s->revision < OMAP2_INTR_REV)
415
 
            OMAP_RO_REG(addr);
416
 
        else {
417
 
            /* RRDY and XRDY are reset by hardware. (in all versions???) */
418
 
            if (s->revision < OMAP3_INTR_REV) {
419
 
                value &= 0x27;
420
 
            } else if (s->revision == OMAP3_INTR_REV) {
421
 
                value &= 0x63e7;
422
 
            } else { /* omap3630 */
423
 
                value &= 0x6ee7;
424
 
            }
425
 
            s->stat &= ~value;
426
 
            omap_i2c_interrupts_update(s);
427
 
        }
428
 
        break;
429
 
 
430
 
    case 0x0c: /* I2C_IV / I2C_WE */
431
 
        if (s->revision < OMAP3_INTR_REV) {
432
 
            OMAP_RO_REG(addr);
433
 
        } else if (s->revision == OMAP3_INTR_REV) {
434
 
            s->we = value & 0x636f;
435
 
        } else { /* omap3630 */
436
 
            s->we = value & 0x6f6f;
437
 
        }
438
 
        break;
439
 
 
440
 
    case 0x14:  /* I2C_BUF */
441
 
        if (s->revision < OMAP3_INTR_REV)
442
 
            s->dma = value & 0x8080;
443
 
        else {
444
 
            s->dma = value & 0xbfbf;
445
 
            if ((value & (1 << 14))    /* RXFIFO_CLR */
446
 
                || (value & (1 << 6))) /* TXFIFO_CLR */
447
 
                s->fifolen = 0;
448
 
        }
449
 
        if (value & (1 << 15))                                  /* RDMA_EN */
450
 
            s->mask &= ~(1 << 3);                               /* RRDY_IE */
451
 
        if (value & (1 << 7))                                   /* XDMA_EN */
452
 
            s->mask &= ~(1 << 4);                               /* XRDY_IE */
453
 
        break;
454
 
 
455
 
    case 0x18:  /* I2C_CNT */
456
 
        s->count = value;                                       /* DCOUNT */
457
 
        break;
458
 
 
459
 
    case 0x1c:  /* I2C_DATA */
460
 
        if (s->revision < OMAP3_INTR_REV) {
461
 
            if (s->fifolen > 2) {
462
 
                /* XXX: remote access (qualifier) error - what's that?  */
463
 
                break;
464
 
            }
465
 
            if (s->control & (1 << 14)) {                               /* BE */
466
 
                s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
467
 
                    (uint8_t)((value >> 8) & 0xff);
468
 
                s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
469
 
                    (uint8_t)(value & 0xff);
470
 
            } else {
471
 
                s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
472
 
                    (uint8_t)(value & 0xff);
473
 
                s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
474
 
                    (uint8_t)((value >> 8) & 0xff);
475
 
            }
476
 
        } else {
477
 
            if (s->fifolen < s->fifosize) {
478
 
                s->stat &= ~(1 << 7); /* AERR */
479
 
                s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
480
 
                    (uint8_t)(value & 0xff);
481
 
            } else
482
 
                s->stat |= (1 << 7); /* AERR */
483
 
        }
484
 
        s->stat &= ~(1 << 10);                                  /* XUDF */
485
 
        omap_i2c_fifo_run(s);
486
 
        omap_i2c_interrupts_update(s);
487
 
        break;
488
 
 
489
 
    case 0x20:  /* I2C_SYSC */
490
 
        if (s->revision < OMAP2_INTR_REV) {
491
 
            OMAP_BAD_REG(addr);
492
 
            break;
493
 
        }
494
 
 
495
 
        if (value & 2) {
496
 
            omap_i2c_reset(DEVICE(s));
497
 
        } else if (s->revision >= OMAP3_INTR_REV) {
498
 
            s->sysc = value & 0x031d;
499
 
        }
500
 
        break;
501
 
 
502
 
    case 0x24:  /* I2C_CON */
503
 
        s->control = value & (s->revision < OMAP3_INTR_REV ? 0xcf87 : 0xbff3);
504
 
        if (~value & (1 << 15)) {                               /* I2C_EN */
505
 
            if (s->revision < OMAP2_INTR_REV) {
506
 
                omap_i2c_reset(DEVICE(s));
507
 
            }
508
 
            break;
509
 
        }
510
 
        if (s->revision >= OMAP3_INTR_REV && ((value >> 12) & 3) > 1) { /* OPMODE */
511
 
            fprintf(stderr,
512
 
                    "%s: only FS and HS modes are supported\n",
513
 
                    __FUNCTION__);
514
 
            break;
515
 
        }
516
 
        if ((value & (1 << 10))) { /* MST */
517
 
            if (value & 1) { /* STT */
518
 
                nack = !!i2c_start_transfer(s->bus, s->slave_addr, /*SA*/
519
 
                                            (~value >> 9) & 1);                 /* TRX */
520
 
                s->stat |= nack << 1;                           /* NACK */
521
 
                s->control &= ~(1 << 0);                                /* STT */
522
 
                s->fifolen = 0;
523
 
                if (nack)
524
 
                    s->control &= ~(1 << 1);                    /* STP */
525
 
                else {
526
 
                    s->count_cur = s->count;
527
 
                    omap_i2c_fifo_run(s);
528
 
                }
529
 
                omap_i2c_interrupts_update(s);
530
 
            } else if (value & 2) { /* STP, but not STT */
531
 
                i2c_end_transfer(s->bus);
532
 
                s->control &= ~0x0602;     /* MST | TRX | STP */
533
 
                s->count_cur = s->count;
534
 
            }
535
 
        }
536
 
        break;
537
 
    case 0x28: /* I2C_OA / I2C_OA0 */
538
 
        s->own_addr[0] = value & (s->revision < OMAP3_INTR_REV
539
 
                                  ? 0x3ff : 0xe3ff);
540
 
        /*i2c_set_slave_address(&s->slave[0],
541
 
          value & (s->revision >= OMAP3_INTR_REV
542
 
          && (s->control & 0x80)
543
 
          ? 0x3ff: 0x7f));*/
544
 
        break;
545
 
 
546
 
    case 0x2c:  /* I2C_SA */
547
 
        s->slave_addr = value & 0x3ff;
548
 
        break;
549
 
 
550
 
    case 0x30:  /* I2C_PSC */
551
 
        s->divider = value;
552
 
        break;
553
 
 
554
 
    case 0x34:  /* I2C_SCLL */
555
 
        s->times[0] = value & (s->revision < OMAP3_INTR_REV ? 0xff : 0xffff);
556
 
        break;
557
 
 
558
 
    case 0x38:  /* I2C_SCLH */
559
 
        s->times[1] = value & (s->revision < OMAP3_INTR_REV ? 0xff : 0xffff);
560
 
        break;
561
 
 
562
 
    case 0x3c:  /* I2C_SYSTEST */
563
 
        if (s->revision < OMAP3_INTR_REV) {
564
 
            value &= 0xf805;
565
 
        } else if (s->revision == OMAP3_INTR_REV) {
566
 
            value &= 0xf815;
567
 
        } else { /* omap3630 */
568
 
            value = (value & 0xf835) | 0x1c00;
569
 
        }
570
 
        if ((value & (1 << 15))) { /* ST_EN */
571
 
            fprintf(stderr, "%s: System Test not supported\n",
572
 
                    __FUNCTION__);
573
 
            s->test = (s->test & 0x0a) | value;
574
 
        } else {
575
 
            value &= ~0xff;
576
 
            s->test = (s->test & 0x1f) | value;
577
 
        }
578
 
        if (value & (1 << 11)) { /* SBB */
579
 
            if (s->revision >= OMAP2_INTR_REV) {
580
 
                s->stat |= 0x3f;
581
 
                if (s->revision >= OMAP3_INTR_REV) {
582
 
                    s->stat |= 0x6300;
583
 
                    if (s->revision > OMAP3_INTR_REV) {
584
 
                        s->stat |= 0x0c00;
585
 
                    }
586
 
                }
587
 
                omap_i2c_interrupts_update(s);
588
 
            }
589
 
        }
590
 
        break;
591
 
 
592
 
    case 0x44: /* I2C_OA1 */
593
 
    case 0x48: /* I2C_OA2 */
594
 
    case 0x4c: /* I2C_OA3 */
595
 
        if (s->revision < OMAP3_INTR_REV)
596
 
            OMAP_BAD_REG(addr);
597
 
        else {
598
 
            addr = (addr >> 2) & 3;
599
 
            s->own_addr[addr] = value & 0x3ff;
600
 
            /*i2c_set_slave_address(&s->slave[addr],
601
 
              value & ((s->control & (0x80 >> addr))
602
 
              ? 0x3ff: 0x7f));*/
603
 
        }
604
 
        break;
605
 
    case 0x54: /* I2C_SBLOCK */
606
 
        if (s->revision < OMAP3_INTR_REV)
607
 
            OMAP_BAD_REG(addr);
608
 
        else {
609
 
            s->sblock = value & 0x0f;
610
 
        }
611
 
        break;
612
 
    default:
613
 
        OMAP_BAD_REG(addr);
614
 
            break;
615
 
    }
616
 
}
617
 
 
618
 
static void omap_i2c_writeb(void *opaque, hwaddr addr,
619
 
                uint32_t value)
620
 
{
621
 
    OMAPI2CState *s = opaque;
622
 
    int offset = addr & OMAP_MPUI_REG_MASK;
623
 
 
624
 
    switch (offset) {
625
 
    case 0x1c:  /* I2C_DATA */
626
 
        if (s->revision < OMAP3_INTR_REV && s->fifolen > 2) {
627
 
            /* XXX: remote access (qualifier) error - what's that?  */
628
 
            break;
629
 
        }
630
 
        if (s->fifolen < s->fifosize) {
631
 
            s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
632
 
                (uint8_t)(value & 0xff);
633
 
            if (s->revision >= OMAP3_INTR_REV)
634
 
                s->stat &= ~(1 << 7); /* AERR */
635
 
            s->stat &= ~(1 << 10);                                      /* XUDF */
636
 
            omap_i2c_fifo_run(s);
637
 
        } else if (s->revision >= OMAP3_INTR_REV)
638
 
            s->stat |= (1 << 7);      /* AERR */
639
 
        omap_i2c_interrupts_update(s);
640
 
        break;
641
 
    default:
642
 
        OMAP_BAD_REG(addr);
643
 
            break;
644
 
    }
645
 
}
646
 
 
647
 
static const MemoryRegionOps omap_i2c_ops = {
648
 
    .old_mmio = {
649
 
        .read = {
650
 
            omap_i2c_readb,
651
 
            omap_i2c_read,
652
 
            omap_badwidth_read16,
653
 
        },
654
 
        .write = {
655
 
            omap_i2c_writeb, /* Only the last fifo write can be 8 bit.  */
656
 
            omap_i2c_write,
657
 
            omap_badwidth_write16,
658
 
        },
659
 
    },
660
 
    .endianness = DEVICE_NATIVE_ENDIAN,
661
 
};
662
 
 
663
 
static int omap_i2c_bus_post_load(void *opaque, int version_id)
664
 
{
665
 
    OMAPI2CState *s = opaque;
666
 
    omap_i2c_interrupts_update(s);
667
 
    return 0;
668
 
}
669
 
 
670
 
static const VMStateDescription vmstate_omap_i2c = {
671
 
    .name = "omap_i2c",
672
 
    .version_id = 1,
673
 
    .minimum_version_id = 1,
674
 
    .post_load = omap_i2c_bus_post_load,
675
 
    .fields = (VMStateField[]) {
676
 
        VMSTATE_UINT16(mask, OMAPI2CState),
677
 
        VMSTATE_UINT16(stat, OMAPI2CState),
678
 
        VMSTATE_UINT16(we, OMAPI2CState),
679
 
        VMSTATE_UINT16(dma, OMAPI2CState),
680
 
        VMSTATE_UINT16(count, OMAPI2CState),
681
 
        VMSTATE_INT32(count_cur, OMAPI2CState),
682
 
        VMSTATE_UINT16(sysc, OMAPI2CState),
683
 
        VMSTATE_UINT16(control, OMAPI2CState),
684
 
        VMSTATE_UINT16_ARRAY(own_addr, OMAPI2CState, 4),
685
 
        VMSTATE_UINT16(slave_addr, OMAPI2CState),
686
 
        VMSTATE_UINT8(sblock, OMAPI2CState),
687
 
        VMSTATE_UINT8(divider, OMAPI2CState),
688
 
        VMSTATE_UINT16_ARRAY(times, OMAPI2CState, 2),
689
 
        VMSTATE_UINT16(test, OMAPI2CState),
690
 
        VMSTATE_INT32(fifostart, OMAPI2CState),
691
 
        VMSTATE_INT32(fifolen, OMAPI2CState),
692
 
        VMSTATE_UINT8_ARRAY(fifo, OMAPI2CState, I2C_MAX_FIFO_SIZE),
693
 
        VMSTATE_END_OF_LIST()
694
 
    }
695
 
};
696
 
 
697
 
static int omap_i2c_init(SysBusDevice *sbd)
698
 
{
699
 
    DeviceState *dev = DEVICE(sbd);
700
 
    OMAPI2CState *s = OMAP_I2C(dev);
701
 
 
702
 
    if (!s->fclk) {
703
 
        hw_error("omap_i2c: fclk not connected\n");
704
 
    }
705
 
    if (s->revision >= OMAP2_INTR_REV && !s->iclk) {
706
 
        /* Note that OMAP1 doesn't have a separate interface clock */
707
 
        hw_error("omap_i2c: iclk not connected\n");
708
 
    }
709
 
    sysbus_init_irq(sbd, &s->irq);
710
 
    sysbus_init_irq(sbd, &s->drq[0]);
711
 
    sysbus_init_irq(sbd, &s->drq[1]);
712
 
    memory_region_init_io(&s->iomem, OBJECT(s), &omap_i2c_ops, s, "omap.i2c",
713
 
                          (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000);
714
 
    sysbus_init_mmio(sbd, &s->iomem);
715
 
    s->bus = i2c_init_bus(dev, NULL);
716
 
    return 0;
717
 
}
718
 
 
719
 
static Property omap_i2c_properties[] = {
720
 
    DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0),
721
 
    DEFINE_PROP_UINT32("fifo-size", OMAPI2CState, fifosize, 4),
722
 
    DEFINE_PROP_PTR("iclk", OMAPI2CState, iclk),
723
 
    DEFINE_PROP_PTR("fclk", OMAPI2CState, fclk),
724
 
    DEFINE_PROP_END_OF_LIST(),
725
 
};
726
 
 
727
 
static void omap_i2c_class_init(ObjectClass *klass, void *data)
728
 
{
729
 
    DeviceClass *dc = DEVICE_CLASS(klass);
730
 
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
731
 
    k->init = omap_i2c_init;
732
 
    dc->props = omap_i2c_properties;
733
 
    dc->reset = omap_i2c_reset;
734
 
    dc->vmsd = &vmstate_omap_i2c;
735
 
}
736
 
 
737
 
static const TypeInfo omap_i2c_info = {
738
 
    .name = TYPE_OMAP_I2C,
739
 
    .parent = TYPE_SYS_BUS_DEVICE,
740
 
    .instance_size = sizeof(OMAPI2CState),
741
 
    .class_init = omap_i2c_class_init,
742
 
};
743
 
 
744
 
static void omap_i2c_register_types(void)
745
 
{
746
 
    type_register_static(&omap_i2c_info);
747
 
}
748
 
 
749
 
i2c_bus *omap_i2c_bus(DeviceState *omap_i2c)
750
 
{
751
 
    OMAPI2CState *s = OMAP_I2C(omap_i2c);
752
 
    return s->bus;
753
 
}
754
 
 
755
 
type_init(omap_i2c_register_types)