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

« back to all changes in this revision

Viewing changes to .pc/linaro-patches/0023-hw-omap_i2c.c-Avoid-infinite-loop-for-byte-wide-writ.patch/hw/i2c/omap_i2c.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2013-10-22 22:47:07 UTC
  • mfrom: (1.8.3) (10.1.42 sid)
  • Revision ID: package-import@ubuntu.com-20131022224707-1lya34fw3k3f24tv
Tags: 1.6.0+dfsg-2ubuntu1
* Merge 1.6.0~rc0+dfsg-2exp from debian experimental.  Remaining changes:
  - debian/control
    * update maintainer
    * remove libiscsi, usb-redir, vde, vnc-jpeg, and libssh2-1-dev
      from build-deps
    * enable rbd
    * add qemu-system and qemu-common B/R to qemu-keymaps
    * add D:udev, R:qemu, R:qemu-common and B:qemu-common to
      qemu-system-common
    * qemu-system-arm, qemu-system-ppc, qemu-system-sparc:
      - add qemu-kvm to Provides
      - add qemu-common, qemu-kvm, kvm to B/R
      - remove openbios-sparc from qemu-system-sparc D
      - drop openbios-ppc and openhackware Depends to Suggests (for now)
    * qemu-system-x86:
      - add qemu-common to Breaks/Replaces.
      - add cpu-checker to Recommends.
    * qemu-user: add B/R:qemu-kvm
    * qemu-kvm:
      - add armhf armel powerpc sparc to Architecture
      - C/R/P: qemu-kvm-spice
    * add qemu-common package
    * drop qemu-slof which is not packaged in ubuntu
  - add qemu-system-common.links for tap ifup/down scripts and OVMF link.
  - qemu-system-x86.links:
    * remove pxe rom links which are in kvm-ipxe
    * add symlink for kvm.1 manpage
  - debian/rules
    * add kvm-spice symlink to qemu-kvm
    * call dh_installmodules for qemu-system-x86
    * update dh_installinit to install upstart script
    * run dh_installman (Closes: #709241) (cherrypicked from 1.5.0+dfsg-2)
  - Add qemu-utils.links for kvm-* symlinks.
  - Add qemu-system-x86.qemu-kvm.upstart and .default
  - Add qemu-system-x86.modprobe to set nesting=1
  - Add qemu-system-common.preinst to add kvm group
  - qemu-system-common.postinst: remove bad group acl if there, then have
    udev relabel /dev/kvm.
  - New linaro patches from qemu-linaro rebasing branch
  - Dropped patches:
    * xen-simplify-xen_enabled.patch
    * sparc-linux-user-fix-missing-symbols-in-.rel-.rela.plt-sections.patch
    * main_loop-do-not-set-nonblocking-if-xen_enabled.patch
    * xen_machine_pv-do-not-create-a-dummy-CPU-in-machine-.patch
    * virtio-rng-fix-crash
  - Kept patches:
    * expose_vms_qemu64cpu.patch - updated
    * linaro arm patches from qemu-linaro rebasing branch
  - New patches:
    * fix-pci-add: change CONFIG variable in ifdef to make sure that
      pci_add is defined.
* Add linaro patches
* Add experimental mach-virt patches for arm virtualization.
* qemu-system-common.install: add debian/tmp/usr/lib to install the
  qemu-bridge-helper

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
            if ((s->control >> 1) & 1) {                        /* STP */
 
149
                i2c_end_transfer(s->bus);
 
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
        return s->stat | (i2c_bus_busy(s->bus) << 12);
 
204
 
 
205
    case 0x0c: /* I2C_IV / I2C_WE */
 
206
        if (s->revision >= OMAP3_INTR_REV)
 
207
            return s->we;
 
208
        if (s->revision >= OMAP2_INTR_REV)
 
209
            break;
 
210
        ret = ffs(s->stat & s->mask);
 
211
        if (ret)
 
212
            s->stat ^= 1 << (ret - 1);
 
213
        omap_i2c_interrupts_update(s);
 
214
        return ret;
 
215
 
 
216
    case 0x10:  /* I2C_SYSS */
 
217
        return (s->control >> 15) & 1;                          /* I2C_EN */
 
218
 
 
219
    case 0x14:  /* I2C_BUF */
 
220
        return s->dma;
 
221
 
 
222
    case 0x18:  /* I2C_CNT */
 
223
        return s->count_cur;                                    /* DCOUNT */
 
224
 
 
225
    case 0x1c:  /* I2C_DATA */
 
226
        ret = 0;
 
227
        if (s->fifolen) {
 
228
            if (s->revision < OMAP3_INTR_REV) {
 
229
                if (s->control & (1 << 14)) /* BE */
 
230
                    ret = (((uint16_t)s->fifo[s->fifostart]) << 8) 
 
231
                        | s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK];
 
232
                else
 
233
                    ret = (((uint16_t)s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK]) << 8) 
 
234
                        | s->fifo[s->fifostart];
 
235
                s->fifostart = (s->fifostart + 2) & I2C_FIFO_SIZE_MASK;
 
236
                if (s->fifolen == 1) {
 
237
                    s->stat |= 1 << 15;                                 /* SBD */
 
238
                    s->fifolen = 0;
 
239
                } else
 
240
                    s->fifolen -= 2;
 
241
                if (!s->fifolen) {
 
242
                    s->stat &= ~(1 << 3); /* RRDY */
 
243
                    s->stat |= 1 << 2;    /* ARDY */
 
244
                }
 
245
            } else {
 
246
                s->stat &= ~(1 << 7); /* AERR */
 
247
                ret = s->fifo[s->fifostart++];
 
248
                s->fifostart &= I2C_FIFO_SIZE_MASK;
 
249
                if (--s->fifolen) {
 
250
                    if (s->fifolen <= ((s->dma >> 8) & 0x3f)) {
 
251
                        s->stat &= ~(1 << 3);                           /* RRDY */
 
252
                        s->stat |= 1 << 13;   /* RDR */
 
253
                    }
 
254
                } else {
 
255
                    s->stat &= ~((1 << 3) | (1 << 13)); /* RRDY | RDR */
 
256
                    s->stat |= 1 << 2;                          /* ARDY */
 
257
                }
 
258
            }
 
259
            s->stat &= ~(1 << 11);                                      /* ROVR */
 
260
        } else if (s->revision >= OMAP3_INTR_REV)
 
261
            s->stat |= (1 << 7); /* AERR */
 
262
        omap_i2c_fifo_run(s);
 
263
        omap_i2c_interrupts_update(s);
 
264
        return ret;
 
265
 
 
266
    case 0x20:  /* I2C_SYSC */
 
267
        return s->sysc;
 
268
 
 
269
    case 0x24:  /* I2C_CON */
 
270
        return s->control;
 
271
 
 
272
    case 0x28: /* I2C_OA / I2C_OA0 */
 
273
        return s->own_addr[0];
 
274
 
 
275
    case 0x2c:  /* I2C_SA */
 
276
        return s->slave_addr;
 
277
 
 
278
    case 0x30:  /* I2C_PSC */
 
279
        return s->divider;
 
280
 
 
281
    case 0x34:  /* I2C_SCLL */
 
282
        return s->times[0];
 
283
 
 
284
    case 0x38:  /* I2C_SCLH */
 
285
        return s->times[1];
 
286
 
 
287
    case 0x3c:  /* I2C_SYSTEST */
 
288
        if (s->test & (1 << 15)) {                              /* ST_EN */
 
289
            s->test ^= 0xa;
 
290
            return s->test;
 
291
        }
 
292
        return s->test & ~0x300f;
 
293
    case 0x40: /* I2C_BUFSTAT */
 
294
        if (s->revision >= OMAP3_INTR_REV) {
 
295
            switch (s->fifosize) {
 
296
            case 8:  ret = 0x0000; break;
 
297
            case 16: ret = 0x4000; break;
 
298
            case 32: ret = 0x8000; break;
 
299
            case 64: ret = 0xc000; break;
 
300
            default: ret = 0x0000; break;
 
301
            }
 
302
            ret |= ((s->fifolen) & 0x3f) << 8;  /* RXSTAT */
 
303
            ret |= (s->count_cur) & 0x3f;       /* TXSTAT */
 
304
            return ret;
 
305
        }
 
306
        break;
 
307
    case 0x44: /* I2C_OA1 */
 
308
    case 0x48: /* I2C_OA2 */
 
309
    case 0x4c: /* I2C_OA3 */
 
310
        if (s->revision >= OMAP3_INTR_REV)
 
311
            return s->own_addr[(addr >> 2) & 3];
 
312
        break;
 
313
    case 0x50: /* I2C_ACTOA */
 
314
        if (s->revision >= OMAP3_INTR_REV)
 
315
            return 0; /* TODO: determine accessed slave own address */
 
316
        break;
 
317
    case 0x54: /* I2C_SBLOCK */
 
318
        if (s->revision >= OMAP3_INTR_REV)
 
319
            return s->sblock;
 
320
        break;
 
321
    default:
 
322
        break;
 
323
    }
 
324
 
 
325
    OMAP_BAD_REG(addr);
 
326
    return 0;
 
327
}
 
328
 
 
329
static uint32_t omap_i2c_readb(void *opaque, hwaddr addr)
 
330
{
 
331
    OMAPI2CState *s = opaque;
 
332
    int offset = addr & OMAP_MPUI_REG_MASK;
 
333
    uint8_t ret;
 
334
 
 
335
    switch (offset) {
 
336
    case 0x1c: /* I2C_DATA */
 
337
        ret = 0;
 
338
        if (s->fifolen) {
 
339
            if (s->revision < OMAP3_INTR_REV) {
 
340
                if (s->control & (1 << 14)) /* BE */
 
341
                    ret = (((uint8_t)s->fifo[s->fifostart]) << 8)
 
342
                        | s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK];
 
343
                else
 
344
                    ret = (((uint8_t)s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK]) << 8)
 
345
                        | s->fifo[s->fifostart];
 
346
                s->fifostart = (s->fifostart + 2) & I2C_FIFO_SIZE_MASK;
 
347
                if (s->fifolen == 1) {
 
348
                    s->stat |= 1 << 15; /* SBD */
 
349
                    s->fifolen = 0;
 
350
                } else
 
351
                    s->fifolen -= 2;
 
352
                if (!s->fifolen) {
 
353
                    s->stat &= ~(1 << 3); /* RRDY */
 
354
                    s->stat |= 1 << 2;    /* ARDY */
 
355
                }
 
356
            } else {
 
357
                s->stat &= ~(1 << 7); /* AERR */
 
358
                ret = (uint8_t)s->fifo[s->fifostart++];
 
359
                s->fifostart &= I2C_FIFO_SIZE_MASK;
 
360
                if (--s->fifolen) {
 
361
                    if (s->fifolen <= ((s->dma >> 8) & 0x3f)) {
 
362
                        s->stat &= ~(1 << 3); /* RRDY */
 
363
                        s->stat |= 1 << 13;   /* RDR */
 
364
                    }
 
365
                } else {
 
366
                    s->stat &= ~((1 << 3) | (1 << 13)); /* RRDY | RDR */
 
367
                    s->stat |= 1 << 2;                  /* ARDY */
 
368
                }
 
369
            }
 
370
            s->stat &= ~(1 << 11); /* ROVR */
 
371
        } else if (s->revision >= OMAP3_INTR_REV)
 
372
            s->stat |= (1 << 7); /* AERR */
 
373
        omap_i2c_fifo_run(s);
 
374
        omap_i2c_interrupts_update(s);
 
375
        return ret;
 
376
    default:
 
377
        break;
 
378
    }
 
379
 
 
380
    OMAP_BAD_REG(addr);
 
381
    return 0;
 
382
}
 
383
 
 
384
static void omap_i2c_write(void *opaque, hwaddr addr,
 
385
                uint32_t value)
 
386
{
 
387
    OMAPI2CState *s = opaque;
 
388
    int offset = addr & OMAP_MPUI_REG_MASK;
 
389
    int nack;
 
390
 
 
391
    switch (offset) {
 
392
    case 0x00:  /* I2C_REV */
 
393
    case 0x10:  /* I2C_SYSS */
 
394
    case 0x40: /* I2C_BUFSTAT */
 
395
    case 0x50: /* I2C_ACTOA */
 
396
        OMAP_RO_REG(addr);
 
397
        break;
 
398
    case 0x04:  /* I2C_IE */
 
399
        if (s->revision < OMAP2_INTR_REV) {
 
400
            s->mask = value & 0x1f;
 
401
        } else if (s->revision < OMAP3_INTR_REV) {
 
402
            s->mask = value & 0x3f;
 
403
        } else if (s->revision == OMAP3_INTR_REV) {
 
404
            s->mask = value & 0x63ff;
 
405
        } else { /* omap3630 */
 
406
            s->mask = value & 0x6fff;
 
407
        }
 
408
        omap_i2c_interrupts_update(s);
 
409
        break;
 
410
    case 0x08:  /* I2C_STAT */
 
411
        if (s->revision < OMAP2_INTR_REV)
 
412
            OMAP_RO_REG(addr);
 
413
        else {
 
414
            /* RRDY and XRDY are reset by hardware. (in all versions???) */
 
415
            if (s->revision < OMAP3_INTR_REV) {
 
416
                value &= 0x27;
 
417
            } else if (s->revision == OMAP3_INTR_REV) {
 
418
                value &= 0x63e7;
 
419
            } else { /* omap3630 */
 
420
                value &= 0x6ee7;
 
421
            }
 
422
            s->stat &= ~value;
 
423
            omap_i2c_interrupts_update(s);
 
424
        }
 
425
        break;
 
426
 
 
427
    case 0x0c: /* I2C_IV / I2C_WE */
 
428
        if (s->revision < OMAP3_INTR_REV) {
 
429
            OMAP_RO_REG(addr);
 
430
        } else if (s->revision == OMAP3_INTR_REV) {
 
431
            s->we = value & 0x636f;
 
432
        } else { /* omap3630 */
 
433
            s->we = value & 0x6f6f;
 
434
        }
 
435
        break;
 
436
 
 
437
    case 0x14:  /* I2C_BUF */
 
438
        if (s->revision < OMAP3_INTR_REV)
 
439
            s->dma = value & 0x8080;
 
440
        else {
 
441
            s->dma = value & 0xbfbf;
 
442
            if ((value & (1 << 14))    /* RXFIFO_CLR */
 
443
                || (value & (1 << 6))) /* TXFIFO_CLR */
 
444
                s->fifolen = 0;
 
445
        }
 
446
        if (value & (1 << 15))                                  /* RDMA_EN */
 
447
            s->mask &= ~(1 << 3);                               /* RRDY_IE */
 
448
        if (value & (1 << 7))                                   /* XDMA_EN */
 
449
            s->mask &= ~(1 << 4);                               /* XRDY_IE */
 
450
        break;
 
451
 
 
452
    case 0x18:  /* I2C_CNT */
 
453
        s->count = value;                                       /* DCOUNT */
 
454
        break;
 
455
 
 
456
    case 0x1c:  /* I2C_DATA */
 
457
        if (s->revision < OMAP3_INTR_REV) {
 
458
            if (s->fifolen > 2) {
 
459
                /* XXX: remote access (qualifier) error - what's that?  */
 
460
                break;
 
461
            }
 
462
            if (s->control & (1 << 14)) {                               /* BE */
 
463
                s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
 
464
                    (uint8_t)((value >> 8) & 0xff);
 
465
                s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
 
466
                    (uint8_t)(value & 0xff);
 
467
            } else {
 
468
                s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
 
469
                    (uint8_t)(value & 0xff);
 
470
                s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
 
471
                    (uint8_t)((value >> 8) & 0xff);
 
472
            }
 
473
        } else {
 
474
            if (s->fifolen < s->fifosize) {
 
475
                s->stat &= ~(1 << 7); /* AERR */
 
476
                s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
 
477
                    (uint8_t)(value & 0xff);
 
478
            } else
 
479
                s->stat |= (1 << 7); /* AERR */
 
480
        }
 
481
        s->stat &= ~(1 << 10);                                  /* XUDF */
 
482
        omap_i2c_fifo_run(s);
 
483
        omap_i2c_interrupts_update(s);
 
484
        break;
 
485
 
 
486
    case 0x20:  /* I2C_SYSC */
 
487
        if (s->revision < OMAP2_INTR_REV) {
 
488
            OMAP_BAD_REG(addr);
 
489
            break;
 
490
        }
 
491
 
 
492
        if (value & 2) {
 
493
            omap_i2c_reset(DEVICE(s));
 
494
        } else if (s->revision >= OMAP3_INTR_REV) {
 
495
            s->sysc = value & 0x031d;
 
496
        }
 
497
        break;
 
498
 
 
499
    case 0x24:  /* I2C_CON */
 
500
        s->control = value & (s->revision < OMAP3_INTR_REV ? 0xcf87 : 0xbff3);
 
501
        if (~value & (1 << 15)) {                               /* I2C_EN */
 
502
            if (s->revision < OMAP2_INTR_REV) {
 
503
                omap_i2c_reset(DEVICE(s));
 
504
            }
 
505
            break;
 
506
        }
 
507
        if (s->revision >= OMAP3_INTR_REV && ((value >> 12) & 3) > 1) { /* OPMODE */
 
508
            fprintf(stderr,
 
509
                    "%s: only FS and HS modes are supported\n",
 
510
                    __FUNCTION__);
 
511
            break;
 
512
        }
 
513
        if ((value & (1 << 10))) { /* MST */
 
514
            if (value & 1) { /* STT */
 
515
                nack = !!i2c_start_transfer(s->bus, s->slave_addr, /*SA*/
 
516
                                            (~value >> 9) & 1);                 /* TRX */
 
517
                s->stat |= nack << 1;                           /* NACK */
 
518
                s->control &= ~(1 << 0);                                /* STT */
 
519
                s->fifolen = 0;
 
520
                if (nack)
 
521
                    s->control &= ~(1 << 1);                    /* STP */
 
522
                else {
 
523
                    s->count_cur = s->count;
 
524
                    omap_i2c_fifo_run(s);
 
525
                }
 
526
                omap_i2c_interrupts_update(s);
 
527
            } else if (value & 2) { /* STP, but not STT */
 
528
                i2c_end_transfer(s->bus);
 
529
                s->control &= ~0x0602;     /* MST | TRX | STP */
 
530
                s->count_cur = s->count;
 
531
            }
 
532
        }
 
533
        break;
 
534
    case 0x28: /* I2C_OA / I2C_OA0 */
 
535
        s->own_addr[0] = value & (s->revision < OMAP3_INTR_REV
 
536
                                  ? 0x3ff : 0xe3ff);
 
537
        /*i2c_set_slave_address(&s->slave[0],
 
538
          value & (s->revision >= OMAP3_INTR_REV
 
539
          && (s->control & 0x80)
 
540
          ? 0x3ff: 0x7f));*/
 
541
        break;
 
542
 
 
543
    case 0x2c:  /* I2C_SA */
 
544
        s->slave_addr = value & 0x3ff;
 
545
        break;
 
546
 
 
547
    case 0x30:  /* I2C_PSC */
 
548
        s->divider = value;
 
549
        break;
 
550
 
 
551
    case 0x34:  /* I2C_SCLL */
 
552
        s->times[0] = value & (s->revision < OMAP3_INTR_REV ? 0xff : 0xffff);
 
553
        break;
 
554
 
 
555
    case 0x38:  /* I2C_SCLH */
 
556
        s->times[1] = value & (s->revision < OMAP3_INTR_REV ? 0xff : 0xffff);
 
557
        break;
 
558
 
 
559
    case 0x3c:  /* I2C_SYSTEST */
 
560
        if (s->revision < OMAP3_INTR_REV) {
 
561
            value &= 0xf805;
 
562
        } else if (s->revision == OMAP3_INTR_REV) {
 
563
            value &= 0xf815;
 
564
        } else { /* omap3630 */
 
565
            value = (value & 0xf835) | 0x1c00;
 
566
        }
 
567
        if ((value & (1 << 15))) { /* ST_EN */
 
568
            fprintf(stderr, "%s: System Test not supported\n",
 
569
                    __FUNCTION__);
 
570
            s->test = (s->test & 0x0a) | value;
 
571
        } else {
 
572
            value &= ~0xff;
 
573
            s->test = (s->test & 0x1f) | value;
 
574
        }
 
575
        if (value & (1 << 11)) { /* SBB */
 
576
            if (s->revision >= OMAP2_INTR_REV) {
 
577
                s->stat |= 0x3f;
 
578
                if (s->revision >= OMAP3_INTR_REV) {
 
579
                    s->stat |= 0x6300;
 
580
                    if (s->revision > OMAP3_INTR_REV) {
 
581
                        s->stat |= 0x0c00;
 
582
                    }
 
583
                }
 
584
                omap_i2c_interrupts_update(s);
 
585
            }
 
586
        }
 
587
        break;
 
588
 
 
589
    case 0x44: /* I2C_OA1 */
 
590
    case 0x48: /* I2C_OA2 */
 
591
    case 0x4c: /* I2C_OA3 */
 
592
        if (s->revision < OMAP3_INTR_REV)
 
593
            OMAP_BAD_REG(addr);
 
594
        else {
 
595
            addr = (addr >> 2) & 3;
 
596
            s->own_addr[addr] = value & 0x3ff;
 
597
            /*i2c_set_slave_address(&s->slave[addr],
 
598
              value & ((s->control & (0x80 >> addr))
 
599
              ? 0x3ff: 0x7f));*/
 
600
        }
 
601
        break;
 
602
    case 0x54: /* I2C_SBLOCK */
 
603
        if (s->revision < OMAP3_INTR_REV)
 
604
            OMAP_BAD_REG(addr);
 
605
        else {
 
606
            s->sblock = value & 0x0f;
 
607
        }
 
608
        break;
 
609
    default:
 
610
        OMAP_BAD_REG(addr);
 
611
            break;
 
612
    }
 
613
}
 
614
 
 
615
static void omap_i2c_writeb(void *opaque, hwaddr addr,
 
616
                uint32_t value)
 
617
{
 
618
    OMAPI2CState *s = opaque;
 
619
    int offset = addr & OMAP_MPUI_REG_MASK;
 
620
 
 
621
    switch (offset) {
 
622
    case 0x1c:  /* I2C_DATA */
 
623
        if (s->revision < OMAP3_INTR_REV && s->fifolen > 2) {
 
624
            /* XXX: remote access (qualifier) error - what's that?  */
 
625
            break;
 
626
        }
 
627
        if (s->fifolen < s->fifosize) {
 
628
            s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
 
629
                (uint8_t)(value & 0xff);
 
630
            if (s->revision >= OMAP3_INTR_REV)
 
631
                s->stat &= ~(1 << 7); /* AERR */
 
632
            s->stat &= ~(1 << 10);                                      /* XUDF */
 
633
            omap_i2c_fifo_run(s);
 
634
        } else if (s->revision >= OMAP3_INTR_REV)
 
635
            s->stat |= (1 << 7);      /* AERR */
 
636
        omap_i2c_interrupts_update(s);
 
637
        break;
 
638
    default:
 
639
        OMAP_BAD_REG(addr);
 
640
            break;
 
641
    }
 
642
}
 
643
 
 
644
static const MemoryRegionOps omap_i2c_ops = {
 
645
    .old_mmio = {
 
646
        .read = {
 
647
            omap_i2c_readb,
 
648
            omap_i2c_read,
 
649
            omap_badwidth_read16,
 
650
        },
 
651
        .write = {
 
652
            omap_i2c_writeb, /* Only the last fifo write can be 8 bit.  */
 
653
            omap_i2c_write,
 
654
            omap_badwidth_write16,
 
655
        },
 
656
    },
 
657
    .endianness = DEVICE_NATIVE_ENDIAN,
 
658
};
 
659
 
 
660
static int omap_i2c_bus_post_load(void *opaque, int version_id)
 
661
{
 
662
    OMAPI2CState *s = opaque;
 
663
    omap_i2c_interrupts_update(s);
 
664
    return 0;
 
665
}
 
666
 
 
667
static const VMStateDescription vmstate_omap_i2c = {
 
668
    .name = "omap_i2c",
 
669
    .version_id = 1,
 
670
    .minimum_version_id = 1,
 
671
    .post_load = omap_i2c_bus_post_load,
 
672
    .fields = (VMStateField[]) {
 
673
        VMSTATE_UINT16(mask, OMAPI2CState),
 
674
        VMSTATE_UINT16(stat, OMAPI2CState),
 
675
        VMSTATE_UINT16(we, OMAPI2CState),
 
676
        VMSTATE_UINT16(dma, OMAPI2CState),
 
677
        VMSTATE_UINT16(count, OMAPI2CState),
 
678
        VMSTATE_INT32(count_cur, OMAPI2CState),
 
679
        VMSTATE_UINT16(sysc, OMAPI2CState),
 
680
        VMSTATE_UINT16(control, OMAPI2CState),
 
681
        VMSTATE_UINT16_ARRAY(own_addr, OMAPI2CState, 4),
 
682
        VMSTATE_UINT16(slave_addr, OMAPI2CState),
 
683
        VMSTATE_UINT8(sblock, OMAPI2CState),
 
684
        VMSTATE_UINT8(divider, OMAPI2CState),
 
685
        VMSTATE_UINT16_ARRAY(times, OMAPI2CState, 2),
 
686
        VMSTATE_UINT16(test, OMAPI2CState),
 
687
        VMSTATE_INT32(fifostart, OMAPI2CState),
 
688
        VMSTATE_INT32(fifolen, OMAPI2CState),
 
689
        VMSTATE_UINT8_ARRAY(fifo, OMAPI2CState, I2C_MAX_FIFO_SIZE),
 
690
        VMSTATE_END_OF_LIST()
 
691
    }
 
692
};
 
693
 
 
694
static int omap_i2c_init(SysBusDevice *sbd)
 
695
{
 
696
    DeviceState *dev = DEVICE(sbd);
 
697
    OMAPI2CState *s = OMAP_I2C(dev);
 
698
 
 
699
    if (!s->fclk) {
 
700
        hw_error("omap_i2c: fclk not connected\n");
 
701
    }
 
702
    if (s->revision >= OMAP2_INTR_REV && !s->iclk) {
 
703
        /* Note that OMAP1 doesn't have a separate interface clock */
 
704
        hw_error("omap_i2c: iclk not connected\n");
 
705
    }
 
706
    sysbus_init_irq(sbd, &s->irq);
 
707
    sysbus_init_irq(sbd, &s->drq[0]);
 
708
    sysbus_init_irq(sbd, &s->drq[1]);
 
709
    memory_region_init_io(&s->iomem, OBJECT(s), &omap_i2c_ops, s, "omap.i2c",
 
710
                          (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000);
 
711
    sysbus_init_mmio(sbd, &s->iomem);
 
712
    s->bus = i2c_init_bus(dev, NULL);
 
713
    return 0;
 
714
}
 
715
 
 
716
static Property omap_i2c_properties[] = {
 
717
    DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0),
 
718
    DEFINE_PROP_UINT32("fifo-size", OMAPI2CState, fifosize, 4),
 
719
    DEFINE_PROP_PTR("iclk", OMAPI2CState, iclk),
 
720
    DEFINE_PROP_PTR("fclk", OMAPI2CState, fclk),
 
721
    DEFINE_PROP_END_OF_LIST(),
 
722
};
 
723
 
 
724
static void omap_i2c_class_init(ObjectClass *klass, void *data)
 
725
{
 
726
    DeviceClass *dc = DEVICE_CLASS(klass);
 
727
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
728
    k->init = omap_i2c_init;
 
729
    dc->props = omap_i2c_properties;
 
730
    dc->reset = omap_i2c_reset;
 
731
    dc->vmsd = &vmstate_omap_i2c;
 
732
}
 
733
 
 
734
static const TypeInfo omap_i2c_info = {
 
735
    .name = TYPE_OMAP_I2C,
 
736
    .parent = TYPE_SYS_BUS_DEVICE,
 
737
    .instance_size = sizeof(OMAPI2CState),
 
738
    .class_init = omap_i2c_class_init,
 
739
};
 
740
 
 
741
static void omap_i2c_register_types(void)
 
742
{
 
743
    type_register_static(&omap_i2c_info);
 
744
}
 
745
 
 
746
i2c_bus *omap_i2c_bus(DeviceState *omap_i2c)
 
747
{
 
748
    OMAPI2CState *s = OMAP_I2C(omap_i2c);
 
749
    return s->bus;
 
750
}
 
751
 
 
752
type_init(omap_i2c_register_types)