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

« back to all changes in this revision

Viewing changes to debian/patches/linaro/0028-hw-omap_spi.c-prepare-for-omap3.patch

  • 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
 
From 96b4a54e6bdca838be30a9b807af0ee2b5340c82 Mon Sep 17 00:00:00 2001
2
 
From: Riku Voipio <riku.voipio@nokia.com>
3
 
Date: Mon, 18 Feb 2013 16:58:28 +0000
4
 
Subject: [PATCH 28/70] hw/omap_spi.c prepare for omap3
5
 
 
6
 
---
7
 
 hw/arm/omap2.c        |   4 +-
8
 
 hw/ssi/omap_spi.c     | 409 +++++++++++++++++++++++++++++++++++++++++---------
9
 
 include/hw/arm/omap.h |   6 +-
10
 
 3 files changed, 343 insertions(+), 76 deletions(-)
11
 
 
12
 
diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c
13
 
index 2a0b45f..81f21a4 100644
14
 
--- a/hw/arm/omap2.c
15
 
+++ b/hw/arm/omap2.c
16
 
@@ -2464,12 +2464,12 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem,
17
 
                     &s->drq[OMAP24XX_DMA_MMC1_TX],
18
 
                     omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk"));
19
 
 
20
 
-    s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4,
21
 
+    s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), s, 4,
22
 
                     qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI1_IRQ),
23
 
                     &s->drq[OMAP24XX_DMA_SPI1_TX0],
24
 
                     omap_findclk(s, "spi1_fclk"),
25
 
                     omap_findclk(s, "spi1_iclk"));
26
 
-    s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2,
27
 
+    s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), s, 2,
28
 
                     qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI2_IRQ),
29
 
                     &s->drq[OMAP24XX_DMA_SPI2_TX0],
30
 
                     omap_findclk(s, "spi2_fclk"),
31
 
diff --git a/hw/ssi/omap_spi.c b/hw/ssi/omap_spi.c
32
 
index 0ed3b11..562d90f 100644
33
 
--- a/hw/ssi/omap_spi.c
34
 
+++ b/hw/ssi/omap_spi.c
35
 
@@ -22,11 +22,25 @@
36
 
 #include "hw/hw.h"
37
 
 #include "hw/arm/omap.h"
38
 
 
39
 
-/* Multichannel SPI */
40
 
+//#define SPI_DEBUG
41
 
+
42
 
+#ifdef SPI_DEBUG
43
 
+#define TRACE(fmt,...) fprintf(stderr, "%s@%d: " fmt "\n", __FUNCTION__, \
44
 
+                               __LINE__, ##__VA_ARGS__);
45
 
+#else
46
 
+#define TRACE(...)
47
 
+#endif
48
 
+
49
 
+#define SPI_FIFOSIZE 64
50
 
+#define SPI_REV_OMAP2420 0x14
51
 
+#define SPI_REV_OMAP3430 0x21
52
 
+#define IS_OMAP3_SPI(s) ((s)->revision >= SPI_REV_OMAP3430)
53
 
+
54
 
 struct omap_mcspi_s {
55
 
     MemoryRegion iomem;
56
 
     qemu_irq irq;
57
 
     int chnum;
58
 
+    uint8_t revision;
59
 
 
60
 
     uint32_t sysconfig;
61
 
     uint32_t systest;
62
 
@@ -35,6 +49,16 @@ struct omap_mcspi_s {
63
 
     uint32_t wken;
64
 
     uint32_t control;
65
 
 
66
 
+    uint32_t xferlevel;
67
 
+    struct omap_mcspi_fifo_s {
68
 
+        int start;
69
 
+        int len;
70
 
+        int size;
71
 
+        uint8_t buf[SPI_FIFOSIZE];
72
 
+    } tx_fifo, rx_fifo;
73
 
+    int fifo_ch;
74
 
+    int fifo_wcnt;
75
 
+
76
 
     struct omap_mcspi_ch_s {
77
 
         qemu_irq txdrq;
78
 
         qemu_irq rxdrq;
79
 
@@ -47,7 +71,7 @@ struct omap_mcspi_s {
80
 
         uint32_t config;
81
 
         uint32_t status;
82
 
         uint32_t control;
83
 
-    } ch[4];
84
 
+    } ch[0];
85
 
 };
86
 
 
87
 
 static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s)
88
 
@@ -55,57 +79,167 @@ static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s)
89
 
     qemu_set_irq(s->irq, s->irqst & s->irqen);
90
 
 }
91
 
 
92
 
-static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_ch_s *ch)
93
 
+static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_s *s,
94
 
+                                                int chnum)
95
 
+{
96
 
+    struct omap_mcspi_ch_s *ch = &s->ch[chnum];
97
 
+    if ((ch->control & 1) &&                         /* EN */
98
 
+        (ch->config & (1 << 14)) &&                  /* DMAW */
99
 
+        (ch->status & (1 << 1)) &&                   /* TXS */
100
 
+        ((ch->config >> 12) & 3) != 1) {             /* TRM */
101
 
+        if (!IS_OMAP3_SPI(s) ||
102
 
+            !(ch->config & (1 << 27)) ||             /* FFEW */
103
 
+            s->tx_fifo.len <= (s->xferlevel & 0x3f)) /* AEL */
104
 
+            qemu_irq_raise(ch->txdrq);
105
 
+        else
106
 
+            qemu_irq_lower(ch->txdrq);
107
 
+    }
108
 
+    if ((ch->control & 1) &&                                /* EN */
109
 
+        (ch->config & (1 << 15)) &&                         /* DMAW */
110
 
+        (ch->status & (1 << 0)) &&                          /* RXS */
111
 
+        ((ch->config >> 12) & 3) != 2) {                    /* TRM */
112
 
+        if (!IS_OMAP3_SPI(s) ||
113
 
+            !(ch->config & (1 << 28)) ||                    /* FFER */
114
 
+            s->rx_fifo.len >= ((s->xferlevel >> 8) & 0x3f)) /* AFL */
115
 
+            qemu_irq_raise(ch->rxdrq);
116
 
+        else
117
 
+            qemu_irq_lower(ch->rxdrq);
118
 
+    }
119
 
+}
120
 
+
121
 
+static void omap_mcspi_fifo_reset(struct omap_mcspi_s *s)
122
 
 {
123
 
-    qemu_set_irq(ch->txdrq,
124
 
-                    (ch->control & 1) &&               /* EN */
125
 
-                    (ch->config & (1 << 14)) &&                /* DMAW */
126
 
-                    (ch->status & (1 << 1)) &&         /* TXS */
127
 
-                    ((ch->config >> 12) & 3) != 1);    /* TRM */
128
 
-    qemu_set_irq(ch->rxdrq,
129
 
-                    (ch->control & 1) &&               /* EN */
130
 
-                    (ch->config & (1 << 15)) &&                /* DMAW */
131
 
-                    (ch->status & (1 << 0)) &&         /* RXS */
132
 
-                    ((ch->config >> 12) & 3) != 2);    /* TRM */
133
 
+    struct omap_mcspi_ch_s *ch;
134
 
+
135
 
+    s->tx_fifo.len = 0;
136
 
+    s->rx_fifo.len = 0;
137
 
+    s->tx_fifo.start = 0;
138
 
+    s->rx_fifo.start = 0;
139
 
+    if (s->fifo_ch < 0) {
140
 
+        s->tx_fifo.size  = s->rx_fifo.size  = 0;
141
 
+    } else {
142
 
+        ch = &s->ch[s->fifo_ch];
143
 
+        s->tx_fifo.size = ((ch->config >> 27) & 1) ? SPI_FIFOSIZE : 0;
144
 
+        s->rx_fifo.size = ((ch->config >> 28) & 1) ? SPI_FIFOSIZE : 0;
145
 
+        if (((ch->config >> 27) & 3) == 3) {
146
 
+            s->tx_fifo.size >>= 1;
147
 
+            s->rx_fifo.size >>= 1;
148
 
+        }
149
 
+    }
150
 
+}
151
 
+
152
 
+/* returns next word in FIFO or the n first bytes if there is not
153
 
+ * enough data in FIFO */
154
 
+static uint32_t omap_mcspi_fifo_get(struct omap_mcspi_fifo_s *s, int wl)
155
 
+{
156
 
+    uint32_t v, sh;
157
 
+
158
 
+    for (v = 0, sh = 0; wl > 0 && s->len; wl -= 8, s->len--, sh += 8) {
159
 
+        v |= ((uint32_t)s->buf[s->start++]) << sh;
160
 
+        if (s->start >= s->size)
161
 
+            s->start = 0;
162
 
+    }
163
 
+    return v;
164
 
+}
165
 
+
166
 
+/* pushes a word to FIFO or the first n bytes of the word if the FIFO
167
 
+ * is too full to hold the full word */
168
 
+static void omap_mcspi_fifo_put(struct omap_mcspi_fifo_s *s, int wl,
169
 
+                                uint32_t v)
170
 
+{
171
 
+    int p = s->start + s->len;
172
 
+
173
 
+    for (; wl > 0 && s->len < s->size; wl -=8, v >>= 8, s->len++) {
174
 
+        if (p >= s->size)
175
 
+            p -= s->size;
176
 
+        s->buf[p++] = (uint8_t)(v & 0xff);
177
 
+    }
178
 
 }
179
 
 
180
 
 static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum)
181
 
 {
182
 
     struct omap_mcspi_ch_s *ch = s->ch + chnum;
183
 
+    int trm = (ch->config >> 12) & 3;
184
 
+    int wl;
185
 
 
186
 
-    if (!(ch->control & 1))                            /* EN */
187
 
+    if (!(ch->control & 1))                  /* EN */
188
 
         return;
189
 
-    if ((ch->status & (1 << 0)) &&                     /* RXS */
190
 
-                    ((ch->config >> 12) & 3) != 2 &&   /* TRM */
191
 
-                    !(ch->config & (1 << 19)))         /* TURBO */
192
 
+    if ((ch->status & 1) && trm != 2 &&      /* RXS */
193
 
+        !(ch->config & (1 << 19)))           /* TURBO */
194
 
         goto intr_update;
195
 
-    if ((ch->status & (1 << 1)) &&                     /* TXS */
196
 
-                    ((ch->config >> 12) & 3) != 1)     /* TRM */
197
 
+    if ((ch->status & (1 << 1)) && trm != 1) /* TXS */
198
 
         goto intr_update;
199
 
 
200
 
-    if (!(s->control & 1) ||                           /* SINGLE */
201
 
-                    (ch->config & (1 << 20))) {                /* FORCE */
202
 
-        if (ch->txrx)
203
 
-            ch->rx = ch->txrx(ch->opaque, ch->tx,      /* WL */
204
 
-                            1 + (0x1f & (ch->config >> 7)));
205
 
+    if (!(s->control & 1) ||        /* SINGLE */
206
 
+        (ch->config & (1 << 20))) { /* FORCE */
207
 
+        if (ch->txrx) {
208
 
+            wl = 1 + (0x1f & (ch->config >> 7)); /* WL */
209
 
+            if (!IS_OMAP3_SPI(s) || s->fifo_ch != chnum ||
210
 
+                !((ch->config >> 27) & 3)) {     /* FFER | FFEW */
211
 
+                ch->rx = ch->txrx(ch->opaque, ch->tx, wl);
212
 
+            } else {
213
 
+                switch ((ch->config >> 27) & 3) {
214
 
+                case 1: /* !FFER, FFEW */
215
 
+                    if (trm != 1)
216
 
+                        ch->tx = omap_mcspi_fifo_get(&s->tx_fifo, wl);
217
 
+                    ch->rx = ch->txrx(ch->opaque, ch->tx, wl);
218
 
+                    s->fifo_wcnt--;
219
 
+                    break;
220
 
+                case 2: /* FFER, !FFEW */
221
 
+                    ch->rx = ch->txrx(ch->opaque, ch->tx, wl);
222
 
+                    if (trm != 2)
223
 
+                        omap_mcspi_fifo_put(&s->rx_fifo, wl, ch->rx);
224
 
+                    s->fifo_wcnt--;
225
 
+                    break;
226
 
+                case 3: /* FFER, FFEW */
227
 
+                    while (s->rx_fifo.len < s->rx_fifo.size &&
228
 
+                           s->tx_fifo.len && s->fifo_wcnt) {
229
 
+                        if (trm != 1)
230
 
+                            ch->tx = omap_mcspi_fifo_get(&s->tx_fifo, wl);
231
 
+                        ch->rx = ch->txrx(ch->opaque, ch->tx, wl);
232
 
+                        if (trm != 2)
233
 
+                            omap_mcspi_fifo_put(&s->rx_fifo, wl, ch->rx);
234
 
+                        s->fifo_wcnt--;
235
 
+                    }
236
 
+                    break;
237
 
+                default:
238
 
+                    break;
239
 
+                }
240
 
+                if ((ch->config & (1 << 28)) &&        /* FFER */
241
 
+                    s->rx_fifo.len >= s->rx_fifo.size)
242
 
+                    ch->status |= 1 << 6;              /* RXFFF */
243
 
+                ch->status &= ~(1 << 5);               /* RXFFE */
244
 
+                ch->status &= ~(1 << 4);               /* TXFFF */
245
 
+                if ((ch->config & (1 << 27)) &&        /* FFEW */
246
 
+                    !s->tx_fifo.len)
247
 
+                    ch->status |= 1 << 3;              /* TXFFE */
248
 
+                if (!s->fifo_wcnt &&
249
 
+                    ((s->xferlevel >> 16) & 0xffff))   /* WCNT */
250
 
+                    s->irqst |= 1 << 17;               /* EOW */
251
 
+            }
252
 
+        }
253
 
     }
254
 
 
255
 
     ch->tx = 0;
256
 
-    ch->status |= 1 << 2;                              /* EOT */
257
 
-    ch->status |= 1 << 1;                              /* TXS */
258
 
-    if (((ch->config >> 12) & 3) != 2)                 /* TRM */
259
 
-        ch->status |= 1 << 0;                          /* RXS */
260
 
+    ch->status |= 1 << 2;               /* EOT */
261
 
+    ch->status |= 1 << 1;               /* TXS */
262
 
+    if (trm != 2)
263
 
+        ch->status |= 1;                /* RXS */
264
 
 
265
 
 intr_update:
266
 
-    if ((ch->status & (1 << 0)) &&                     /* RXS */
267
 
-                    ((ch->config >> 12) & 3) != 2 &&   /* TRM */
268
 
-                    !(ch->config & (1 << 19)))         /* TURBO */
269
 
-        s->irqst |= 1 << (2 + 4 * chnum);              /* RX_FULL */
270
 
-    if ((ch->status & (1 << 1)) &&                     /* TXS */
271
 
-                    ((ch->config >> 12) & 3) != 1)     /* TRM */
272
 
-        s->irqst |= 1 << (0 + 4 * chnum);              /* TX_EMPTY */
273
 
+    if ((ch->status & 1) &&    trm != 2 &&                     /* RXS */
274
 
+        !(ch->config & (1 << 19)))                          /* TURBO */
275
 
+        if (!IS_OMAP3_SPI(s) || s->fifo_ch != chnum ||
276
 
+            !((ch->config >> 28) & 1) ||                    /* FFER */
277
 
+            s->rx_fifo.len >= ((s->xferlevel >> 8) & 0x3f)) /* AFL */
278
 
+            s->irqst |= 1 << (2 + 4 * chnum);               /* RX_FULL */
279
 
+    if ((ch->status & (1 << 1)) && trm != 1)                /* TXS */
280
 
+        if (!IS_OMAP3_SPI(s) || s->fifo_ch != chnum ||
281
 
+            !((ch->config >> 27) & 1) ||                    /* FFEW */
282
 
+            s->tx_fifo.len <= (s->xferlevel & 0x3f))        /* AEL */
283
 
+            s->irqst |= 1 << (4 * chnum);                   /* TX_EMPTY */
284
 
     omap_mcspi_interrupt_update(s);
285
 
-    omap_mcspi_dmarequest_update(ch);
286
 
+    omap_mcspi_dmarequest_update(s, chnum);
287
 
 }
288
 
 
289
 
 void omap_mcspi_reset(struct omap_mcspi_s *s)
290
 
@@ -119,12 +253,15 @@ void omap_mcspi_reset(struct omap_mcspi_s *s)
291
 
     s->wken = 0;
292
 
     s->control = 4;
293
 
 
294
 
-    for (ch = 0; ch < 4; ch ++) {
295
 
+    s->fifo_ch = -1;
296
 
+    omap_mcspi_fifo_reset(s);
297
 
+
298
 
+    for (ch = 0; ch < s->chnum; ch ++) {
299
 
         s->ch[ch].config = 0x060000;
300
 
         s->ch[ch].status = 2;                          /* TXS */
301
 
         s->ch[ch].control = 0;
302
 
 
303
 
-        omap_mcspi_dmarequest_update(s->ch + ch);
304
 
+        omap_mcspi_dmarequest_update(s, ch);
305
 
     }
306
 
 
307
 
     omap_mcspi_interrupt_update(s);
308
 
@@ -143,27 +280,35 @@ static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
309
 
 
310
 
     switch (addr) {
311
 
     case 0x00: /* MCSPI_REVISION */
312
 
-        return 0x91;
313
 
+        TRACE("REVISION = 0x%08x", s->revision);
314
 
+        return s->revision;
315
 
 
316
 
     case 0x10: /* MCSPI_SYSCONFIG */
317
 
+        TRACE("SYSCONFIG = 0x%08x", s->sysconfig);
318
 
         return s->sysconfig;
319
 
 
320
 
     case 0x14: /* MCSPI_SYSSTATUS */
321
 
+        TRACE("SYSSTATUS = 0x00000001");
322
 
         return 1;                                      /* RESETDONE */
323
 
 
324
 
     case 0x18: /* MCSPI_IRQSTATUS */
325
 
+        TRACE("IRQSTATUS = 0x%08x", s->irqst);
326
 
         return s->irqst;
327
 
 
328
 
     case 0x1c: /* MCSPI_IRQENABLE */
329
 
+        TRACE("IRQENABLE = 0x%08x", s->irqen);
330
 
         return s->irqen;
331
 
 
332
 
     case 0x20: /* MCSPI_WAKEUPENABLE */
333
 
+        TRACE("WAKEUPENABLE = 0x%08x", s->wken);
334
 
         return s->wken;
335
 
 
336
 
     case 0x24: /* MCSPI_SYST */
337
 
+        TRACE("SYST = 0x%08x", s->systest);
338
 
         return s->systest;
339
 
 
340
 
     case 0x28: /* MCSPI_MODULCTRL */
341
 
+        TRACE("MODULCTRL = 0x%08x", s->control);
342
 
         return s->control;
343
 
 
344
 
     case 0x68: ch ++;
345
 
@@ -173,7 +318,9 @@ static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
346
 
     case 0x40: ch ++;
347
 
         /* fall through */
348
 
     case 0x2c: /* MCSPI_CHCONF */
349
 
-        return s->ch[ch].config;
350
 
+        TRACE("CHCONF%d = 0x%08x", ch,
351
 
+              (ch < s->chnum) ? s->ch[ch].config : 0);
352
 
+        return (ch < s->chnum) ? s->ch[ch].config : 0;
353
 
 
354
 
     case 0x6c: ch ++;
355
 
         /* fall through */
356
 
@@ -182,7 +329,9 @@ static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
357
 
     case 0x44: ch ++;
358
 
         /* fall through */
359
 
     case 0x30: /* MCSPI_CHSTAT */
360
 
-        return s->ch[ch].status;
361
 
+        TRACE("CHSTAT%d = 0x%08x", ch,
362
 
+              (ch < s->chnum) ? s->ch[ch].status : 0);
363
 
+        return (ch < s->chnum) ? s->ch[ch].status : 0;
364
 
 
365
 
     case 0x70: ch ++;
366
 
         /* fall through */
367
 
@@ -191,7 +340,9 @@ static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
368
 
     case 0x48: ch ++;
369
 
         /* fall through */
370
 
     case 0x34: /* MCSPI_CHCTRL */
371
 
-        return s->ch[ch].control;
372
 
+        TRACE("CHCTRL%d = 0x%08x", ch,
373
 
+              (ch < s->chnum) ? s->ch[ch].control : 0);
374
 
+        return (ch < s->chnum) ? s->ch[ch].control : 0;
375
 
 
376
 
     case 0x74: ch ++;
377
 
         /* fall through */
378
 
@@ -200,7 +351,9 @@ static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
379
 
     case 0x4c: ch ++;
380
 
         /* fall through */
381
 
     case 0x38: /* MCSPI_TX */
382
 
-        return s->ch[ch].tx;
383
 
+        TRACE("TX%d = 0x%08x", ch,
384
 
+              (ch < s->chnum) ? s->ch[ch].tx : 0);
385
 
+        return (ch < s->chnum) ? s->ch[ch].tx : 0;
386
 
 
387
 
     case 0x78: ch ++;
388
 
         /* fall through */
389
 
@@ -209,10 +362,50 @@ static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
390
 
     case 0x50: ch ++;
391
 
         /* fall through */
392
 
     case 0x3c: /* MCSPI_RX */
393
 
-        s->ch[ch].status &= ~(1 << 0);                 /* RXS */
394
 
-        ret = s->ch[ch].rx;
395
 
-        omap_mcspi_transfer_run(s, ch);
396
 
-        return ret;
397
 
+        if (ch < s->chnum) {
398
 
+            if (!IS_OMAP3_SPI(s) || ch != s->fifo_ch ||
399
 
+                !(s->ch[ch].config & (1 << 28))) { /* FFER */
400
 
+                s->ch[ch].status &= ~1;            /* RXS */
401
 
+                ret = s->ch[ch].rx;
402
 
+                TRACE("RX%d = 0x%08x", ch, ret);
403
 
+                omap_mcspi_transfer_run(s, ch);
404
 
+                return ret;
405
 
+            }
406
 
+            if (!s->rx_fifo.len) {
407
 
+                TRACE("rxfifo underflow!");
408
 
+            } else {
409
 
+                qemu_irq_lower(s->ch[ch].rxdrq);
410
 
+                s->ch[ch].status &= ~(1 << 6);                 /* RXFFF */
411
 
+                if (((s->ch[ch].config >> 12) & 3) != 2)        /* TRM */
412
 
+                    ret = omap_mcspi_fifo_get(&s->rx_fifo,
413
 
+                        1 + ((s->ch[ch].config >> 7) & 0x1f)); /* WL */
414
 
+                else
415
 
+                    ret = s->ch[ch].rx;
416
 
+                TRACE("RX%d = 0x%08x", ch, ret);
417
 
+                if (!s->rx_fifo.len) {
418
 
+                    s->ch[ch].status &= ~1;     /* RXS */
419
 
+                    s->ch[ch].status |= 1 << 5; /* RXFFE */
420
 
+                    omap_mcspi_transfer_run(s, ch);
421
 
+                }
422
 
+                return ret;
423
 
+            }
424
 
+        }
425
 
+        TRACE("RX%d = 0x00000000", ch);
426
 
+        return 0;
427
 
+
428
 
+    case 0x7c: /* MCSPI_XFERLEVEL */
429
 
+        if (IS_OMAP3_SPI(s)) {
430
 
+            if ((s->xferlevel >> 16) & 0xffff) /* WCNT */
431
 
+                ret = ((s->xferlevel & 0xffff0000) - (s->fifo_wcnt << 16));
432
 
+            else
433
 
+                ret = ((-s->fifo_wcnt) & 0xffff) << 16;
434
 
+            TRACE("XFERLEVEL = 0x%08x", (s->xferlevel & 0xffff) | ret);
435
 
+            return (s->xferlevel & 0xffff) | ret;
436
 
+        }
437
 
+        break;
438
 
+
439
 
+    default:
440
 
+        break;
441
 
     }
442
 
 
443
 
     OMAP_BAD_REG(addr);
444
 
@@ -223,6 +416,7 @@ static void omap_mcspi_write(void *opaque, hwaddr addr,
445
 
                              uint64_t value, unsigned size)
446
 
 {
447
 
     struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
448
 
+    uint32_t old;
449
 
     int ch = 0;
450
 
 
451
 
     if (size != 4) {
452
 
@@ -240,16 +434,19 @@ static void omap_mcspi_write(void *opaque, hwaddr addr,
453
 
     case 0x64: /* MCSPI_RX2 */
454
 
     case 0x6c: /* MCSPI_CHSTAT3 */
455
 
     case 0x78: /* MCSPI_RX3 */
456
 
-        OMAP_RO_REG(addr);
457
 
+        /* silently ignore */
458
 
+        //OMAP_RO_REGV(addr, value);
459
 
         return;
460
 
 
461
 
     case 0x10: /* MCSPI_SYSCONFIG */
462
 
+        TRACE("SYSCONFIG = 0x%08x", value);
463
 
         if (value & (1 << 1))                          /* SOFTRESET */
464
 
             omap_mcspi_reset(s);
465
 
         s->sysconfig = value & 0x31d;
466
 
         break;
467
 
 
468
 
     case 0x18: /* MCSPI_IRQSTATUS */
469
 
+        TRACE("IRQSTATUS = 0x%08x", value);
470
 
         if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) {
471
 
             s->irqst &= ~value;
472
 
             omap_mcspi_interrupt_update(s);
473
 
@@ -257,15 +454,18 @@ static void omap_mcspi_write(void *opaque, hwaddr addr,
474
 
         break;
475
 
 
476
 
     case 0x1c: /* MCSPI_IRQENABLE */
477
 
-        s->irqen = value & 0x1777f;
478
 
+        TRACE("IRQENABLE = 0x%08x", value);
479
 
+        s->irqen = value & (IS_OMAP3_SPI(s) ? 0x3777f : 0x1777f);
480
 
         omap_mcspi_interrupt_update(s);
481
 
         break;
482
 
 
483
 
     case 0x20: /* MCSPI_WAKEUPENABLE */
484
 
+        TRACE("WAKEUPENABLE = 0x%08x", value);
485
 
         s->wken = value & 1;
486
 
         break;
487
 
 
488
 
     case 0x24: /* MCSPI_SYST */
489
 
+        TRACE("SYST = 0x%08x", value);
490
 
         if (s->control & (1 << 3))                     /* SYSTEM_TEST */
491
 
             if (value & (1 << 11)) {                   /* SSB */
492
 
                 s->irqst |= 0x1777f;
493
 
@@ -275,9 +475,10 @@ static void omap_mcspi_write(void *opaque, hwaddr addr,
494
 
         break;
495
 
 
496
 
     case 0x28: /* MCSPI_MODULCTRL */
497
 
+        TRACE("MODULCTRL = 0x%08x", value);
498
 
         if (value & (1 << 3))                          /* SYSTEM_TEST */
499
 
             if (s->systest & (1 << 11)) {              /* SSB */
500
 
-                s->irqst |= 0x1777f;
501
 
+                s->irqst |= IS_OMAP3_SPI(s) ? 0x3777f : 0x1777f;
502
 
                 omap_mcspi_interrupt_update(s);
503
 
             }
504
 
         s->control = value & 0xf;
505
 
@@ -290,14 +491,30 @@ static void omap_mcspi_write(void *opaque, hwaddr addr,
506
 
     case 0x40: ch ++;
507
 
         /* fall through */
508
 
     case 0x2c: /* MCSPI_CHCONF */
509
 
-        if ((value ^ s->ch[ch].config) & (3 << 14))    /* DMAR | DMAW */
510
 
-            omap_mcspi_dmarequest_update(s->ch + ch);
511
 
-        if (((value >> 12) & 3) == 3)                  /* TRM */
512
 
-            fprintf(stderr, "%s: invalid TRM value (3)\n", __FUNCTION__);
513
 
-        if (((value >> 7) & 0x1f) < 3)                 /* WL */
514
 
-            fprintf(stderr, "%s: invalid WL value (%" PRIx64 ")\n",
515
 
-                            __FUNCTION__, (value >> 7) & 0x1f);
516
 
-        s->ch[ch].config = value & 0x7fffff;
517
 
+        TRACE("CHCONF%d = 0x%08x", ch, value);
518
 
+        if (ch < s->chnum) {
519
 
+            old = s->ch[ch].config;
520
 
+            s->ch[ch].config = value & (IS_OMAP3_SPI(s)
521
 
+                                        ? 0x3fffffff : 0x7fffff);
522
 
+            if (IS_OMAP3_SPI(s) &&
523
 
+                ((value ^ old) & (3 << 27))) { /* FFER | FFEW */
524
 
+                s->fifo_ch = ((value & (3 << 27))) ? ch : -1;
525
 
+                omap_mcspi_fifo_reset(s);
526
 
+            }
527
 
+            if (((value ^ old) & (3 << 14)) || /* DMAR | DMAW */
528
 
+                (IS_OMAP3_SPI(s) &&
529
 
+                 ((value ^ old) & (3 << 27)))) /* FFER | FFEW */
530
 
+                omap_mcspi_dmarequest_update(s, ch);
531
 
+            if (((value >> 12) & 3) == 3) {   /* TRM */
532
 
+                TRACE("invalid TRM value (3)");
533
 
+            }
534
 
+                if (((value >> 7) & 0x1f) < 3) {  /* WL */
535
 
+                TRACE("invalid WL value (%" PRIx64 ")", (value >> 7) & 0x1f);
536
 
+                }
537
 
+            if (IS_OMAP3_SPI(s) && ((value >> 23) & 1)) { /* SBE */
538
 
+                TRACE("start-bit mode is not supported");
539
 
+            }
540
 
+        }
541
 
         break;
542
 
 
543
 
     case 0x70: ch ++;
544
 
@@ -307,11 +524,16 @@ static void omap_mcspi_write(void *opaque, hwaddr addr,
545
 
     case 0x48: ch ++;
546
 
         /* fall through */
547
 
     case 0x34: /* MCSPI_CHCTRL */
548
 
-        if (value & ~s->ch[ch].control & 1) {          /* EN */
549
 
-            s->ch[ch].control |= 1;
550
 
-            omap_mcspi_transfer_run(s, ch);
551
 
-        } else
552
 
-            s->ch[ch].control = value & 1;
553
 
+        TRACE("CHCTRL%d = 0x%08x", ch, value);
554
 
+        if (ch < s->chnum) {
555
 
+            old = s->ch[ch].control;
556
 
+            s->ch[ch].control = value & (IS_OMAP3_SPI(s) ? 0xff01 : 1);
557
 
+            if (value & ~old & 1) { /* EN */
558
 
+                if (IS_OMAP3_SPI(s) && s->fifo_ch == ch)
559
 
+                    omap_mcspi_fifo_reset(s);
560
 
+                omap_mcspi_transfer_run(s, ch);
561
 
+            }
562
 
+        }
563
 
         break;
564
 
 
565
 
     case 0x74: ch ++;
566
 
@@ -321,9 +543,47 @@ static void omap_mcspi_write(void *opaque, hwaddr addr,
567
 
     case 0x4c: ch ++;
568
 
         /* fall through */
569
 
     case 0x38: /* MCSPI_TX */
570
 
-        s->ch[ch].tx = value;
571
 
-        s->ch[ch].status &= ~(1 << 1);                 /* TXS */
572
 
-        omap_mcspi_transfer_run(s, ch);
573
 
+        TRACE("TX%d = 0x%08x", ch, value);
574
 
+        if (ch < s->chnum) {
575
 
+            if (!IS_OMAP3_SPI(s) || s->fifo_ch != ch ||
576
 
+                !(s->ch[ch].config & (1 << 27))) { /* FFEW */
577
 
+                s->ch[ch].tx = value;
578
 
+                s->ch[ch].status &= ~0x06;         /* EOT | TXS */
579
 
+                omap_mcspi_transfer_run(s, ch);
580
 
+            } else {
581
 
+                if (s->tx_fifo.len >= s->tx_fifo.size) {
582
 
+                    TRACE("txfifo overflow!");
583
 
+                } else {
584
 
+                    qemu_irq_lower(s->ch[ch].txdrq);
585
 
+                    s->ch[ch].status &= ~0x0e;      /* TXFFE | EOT | TXS */
586
 
+                    if (((s->ch[ch].config >> 12) & 3) != 1) {    /* TRM */
587
 
+                        omap_mcspi_fifo_put(
588
 
+                            &s->tx_fifo,
589
 
+                            1 + ((s->ch[ch].config >> 7) & 0x1f), /* WL */
590
 
+                            value);
591
 
+                        if (s->tx_fifo.len >= s->tx_fifo.size)
592
 
+                            s->ch[ch].status |= 1 << 4;        /* TXFFF */
593
 
+                        if (s->tx_fifo.len >= (s->xferlevel & 0x3f))
594
 
+                            omap_mcspi_transfer_run(s, ch);
595
 
+                    } else {
596
 
+                        s->ch[ch].tx = value;
597
 
+                        omap_mcspi_transfer_run(s, ch);
598
 
+                    }
599
 
+                }
600
 
+            }
601
 
+        }
602
 
+        break;
603
 
+
604
 
+    case 0x7c: /* MCSPI_XFERLEVEL */
605
 
+        TRACE("XFERLEVEL = 0x%08x", value);
606
 
+        if (IS_OMAP3_SPI(s)) {
607
 
+            if (value != s->xferlevel) {
608
 
+                s->fifo_wcnt = (value >> 16) & 0xffff;
609
 
+                s->xferlevel = value & 0xffff3f3f;
610
 
+                omap_mcspi_fifo_reset(s);
611
 
+            }
612
 
+        } else
613
 
+            OMAP_BAD_REG(addr);
614
 
         break;
615
 
 
616
 
     default:
617
 
@@ -338,15 +598,19 @@ static const MemoryRegionOps omap_mcspi_ops = {
618
 
     .endianness = DEVICE_NATIVE_ENDIAN,
619
 
 };
620
 
 
621
 
-struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
622
 
-                qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
623
 
+struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta,
624
 
+                                     struct omap_mpu_state_s *mpu,
625
 
+                                     int chnum, qemu_irq irq, qemu_irq *drq,
626
 
+                                     omap_clk fclk, omap_clk iclk)
627
 
 {
628
 
-    struct omap_mcspi_s *s = (struct omap_mcspi_s *)
629
 
-            g_malloc0(sizeof(struct omap_mcspi_s));
630
 
+    struct omap_mcspi_s *s = g_malloc0(sizeof(*s) +
631
 
+        chnum * sizeof(struct omap_mcspi_ch_s));
632
 
     struct omap_mcspi_ch_s *ch = s->ch;
633
 
 
634
 
     s->irq = irq;
635
 
     s->chnum = chnum;
636
 
+    /* revision was hardcoded as 0x91 in original code -- odd */
637
 
+    s->revision = cpu_class_omap3(mpu) ? SPI_REV_OMAP3430 : SPI_REV_OMAP2420;
638
 
     while (chnum --) {
639
 
         ch->txdrq = *drq ++;
640
 
         ch->rxdrq = *drq ++;
641
 
@@ -362,8 +626,9 @@ struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
642
 
 }
643
 
 
644
 
 void omap_mcspi_attach(struct omap_mcspi_s *s,
645
 
-                uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
646
 
-                int chipselect)
647
 
+                       uint32_t (*txrx)(void *opaque, uint32_t, int),
648
 
+                       void *opaque,
649
 
+                       int chipselect)
650
 
 {
651
 
     if (chipselect < 0 || chipselect >= s->chnum)
652
 
         hw_error("%s: Bad chipselect %i\n", __FUNCTION__, chipselect);
653
 
diff --git a/include/hw/arm/omap.h b/include/hw/arm/omap.h
654
 
index 161a217..9f2612e 100644
655
 
--- a/include/hw/arm/omap.h
656
 
+++ b/include/hw/arm/omap.h
657
 
@@ -898,8 +898,10 @@ void omap_uwire_attach(struct omap_uwire_s *s,
658
 
 
659
 
 /* OMAP2 spi */
660
 
 struct omap_mcspi_s;
661
 
-struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
662
 
-                qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk);
663
 
+struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta,
664
 
+                                     struct omap_mpu_state_s *mp,
665
 
+                                     int chnum, qemu_irq irq, qemu_irq *drq,
666
 
+                                     omap_clk fclk, omap_clk iclk);
667
 
 void omap_mcspi_attach(struct omap_mcspi_s *s,
668
 
                 uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
669
 
                 int chipselect);
670
 
1.8.5.2
671