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
8
hw/ssi/omap_spi.c | 409 +++++++++++++++++++++++++++++++++++++++++---------
9
include/hw/arm/omap.h | 6 +-
10
3 files changed, 343 insertions(+), 76 deletions(-)
12
diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c
13
index 2a0b45f..81f21a4 100644
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"));
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
37
#include "hw/arm/omap.h"
39
-/* Multichannel SPI */
43
+#define TRACE(fmt,...) fprintf(stderr, "%s@%d: " fmt "\n", __FUNCTION__, \
44
+ __LINE__, ##__VA_ARGS__);
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)
62
@@ -35,6 +49,16 @@ struct omap_mcspi_s {
67
+ struct omap_mcspi_fifo_s {
71
+ uint8_t buf[SPI_FIFOSIZE];
76
struct omap_mcspi_ch_s {
79
@@ -47,7 +71,7 @@ struct omap_mcspi_s {
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);
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,
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);
106
+ qemu_irq_lower(ch->txdrq);
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);
117
+ qemu_irq_lower(ch->rxdrq);
121
+static void omap_mcspi_fifo_reset(struct omap_mcspi_s *s)
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;
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;
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;
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)
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)
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,
171
+ int p = s->start + s->len;
173
+ for (; wl > 0 && s->len < s->size; wl -=8, v >>= 8, s->len++) {
176
+ s->buf[p++] = (uint8_t)(v & 0xff);
180
static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum)
182
struct omap_mcspi_ch_s *ch = s->ch + chnum;
183
+ int trm = (ch->config >> 12) & 3;
186
- if (!(ch->control & 1)) /* EN */
187
+ if (!(ch->control & 1)) /* EN */
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 */
195
- if ((ch->status & (1 << 1)) && /* TXS */
196
- ((ch->config >> 12) & 3) != 1) /* TRM */
197
+ if ((ch->status & (1 << 1)) && trm != 1) /* TXS */
200
- if (!(s->control & 1) || /* SINGLE */
201
- (ch->config & (1 << 20))) { /* FORCE */
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 */
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);
213
+ switch ((ch->config >> 27) & 3) {
214
+ case 1: /* !FFER, FFEW */
216
+ ch->tx = omap_mcspi_fifo_get(&s->tx_fifo, wl);
217
+ ch->rx = ch->txrx(ch->opaque, ch->tx, wl);
220
+ case 2: /* FFER, !FFEW */
221
+ ch->rx = ch->txrx(ch->opaque, ch->tx, wl);
223
+ omap_mcspi_fifo_put(&s->rx_fifo, wl, ch->rx);
226
+ case 3: /* FFER, FFEW */
227
+ while (s->rx_fifo.len < s->rx_fifo.size &&
228
+ s->tx_fifo.len && s->fifo_wcnt) {
230
+ ch->tx = omap_mcspi_fifo_get(&s->tx_fifo, wl);
231
+ ch->rx = ch->txrx(ch->opaque, ch->tx, wl);
233
+ omap_mcspi_fifo_put(&s->rx_fifo, wl, ch->rx);
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 */
247
+ ch->status |= 1 << 3; /* TXFFE */
248
+ if (!s->fifo_wcnt &&
249
+ ((s->xferlevel >> 16) & 0xffff)) /* WCNT */
250
+ s->irqst |= 1 << 17; /* EOW */
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 */
263
+ ch->status |= 1; /* RXS */
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);
289
void omap_mcspi_reset(struct omap_mcspi_s *s)
290
@@ -119,12 +253,15 @@ void omap_mcspi_reset(struct omap_mcspi_s *s)
294
- for (ch = 0; ch < 4; ch ++) {
296
+ omap_mcspi_fifo_reset(s);
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;
303
- omap_mcspi_dmarequest_update(s->ch + ch);
304
+ omap_mcspi_dmarequest_update(s, ch);
307
omap_mcspi_interrupt_update(s);
308
@@ -143,27 +280,35 @@ static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
311
case 0x00: /* MCSPI_REVISION */
313
+ TRACE("REVISION = 0x%08x", s->revision);
314
+ return s->revision;
316
case 0x10: /* MCSPI_SYSCONFIG */
317
+ TRACE("SYSCONFIG = 0x%08x", s->sysconfig);
320
case 0x14: /* MCSPI_SYSSTATUS */
321
+ TRACE("SYSSTATUS = 0x00000001");
322
return 1; /* RESETDONE */
324
case 0x18: /* MCSPI_IRQSTATUS */
325
+ TRACE("IRQSTATUS = 0x%08x", s->irqst);
328
case 0x1c: /* MCSPI_IRQENABLE */
329
+ TRACE("IRQENABLE = 0x%08x", s->irqen);
332
case 0x20: /* MCSPI_WAKEUPENABLE */
333
+ TRACE("WAKEUPENABLE = 0x%08x", s->wken);
336
case 0x24: /* MCSPI_SYST */
337
+ TRACE("SYST = 0x%08x", s->systest);
340
case 0x28: /* MCSPI_MODULCTRL */
341
+ TRACE("MODULCTRL = 0x%08x", s->control);
345
@@ -173,7 +318,9 @@ static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
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;
356
@@ -182,7 +329,9 @@ static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
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;
367
@@ -191,7 +340,9 @@ static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
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;
378
@@ -200,7 +351,9 @@ static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
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;
389
@@ -209,10 +362,50 @@ static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
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);
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);
406
+ if (!s->rx_fifo.len) {
407
+ TRACE("rxfifo underflow!");
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 */
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);
425
+ TRACE("RX%d = 0x00000000", ch);
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));
433
+ ret = ((-s->fifo_wcnt) & 0xffff) << 16;
434
+ TRACE("XFERLEVEL = 0x%08x", (s->xferlevel & 0xffff) | ret);
435
+ return (s->xferlevel & 0xffff) | ret;
444
@@ -223,6 +416,7 @@ static void omap_mcspi_write(void *opaque, hwaddr addr,
445
uint64_t value, unsigned size)
447
struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
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 */
457
+ /* silently ignore */
458
+ //OMAP_RO_REGV(addr, value);
461
case 0x10: /* MCSPI_SYSCONFIG */
462
+ TRACE("SYSCONFIG = 0x%08x", value);
463
if (value & (1 << 1)) /* SOFTRESET */
465
s->sysconfig = value & 0x31d;
468
case 0x18: /* MCSPI_IRQSTATUS */
469
+ TRACE("IRQSTATUS = 0x%08x", value);
470
if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) {
472
omap_mcspi_interrupt_update(s);
473
@@ -257,15 +454,18 @@ static void omap_mcspi_write(void *opaque, hwaddr addr,
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);
483
case 0x20: /* MCSPI_WAKEUPENABLE */
484
+ TRACE("WAKEUPENABLE = 0x%08x", value);
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 */
493
@@ -275,9 +475,10 @@ static void omap_mcspi_write(void *opaque, hwaddr addr,
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);
504
s->control = value & 0xf;
505
@@ -290,14 +491,30 @@ static void omap_mcspi_write(void *opaque, hwaddr addr,
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);
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)");
534
+ if (((value >> 7) & 0x1f) < 3) { /* WL */
535
+ TRACE("invalid WL value (%" PRIx64 ")", (value >> 7) & 0x1f);
537
+ if (IS_OMAP3_SPI(s) && ((value >> 23) & 1)) { /* SBE */
538
+ TRACE("start-bit mode is not supported");
544
@@ -307,11 +524,16 @@ static void omap_mcspi_write(void *opaque, hwaddr addr,
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);
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);
566
@@ -321,9 +543,47 @@ static void omap_mcspi_write(void *opaque, hwaddr addr,
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);
581
+ if (s->tx_fifo.len >= s->tx_fifo.size) {
582
+ TRACE("txfifo overflow!");
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(
589
+ 1 + ((s->ch[ch].config >> 7) & 0x1f), /* WL */
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);
596
+ s->ch[ch].tx = value;
597
+ omap_mcspi_transfer_run(s, ch);
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);
613
+ OMAP_BAD_REG(addr);
617
@@ -338,15 +598,19 @@ static const MemoryRegionOps omap_mcspi_ops = {
618
.endianness = DEVICE_NATIVE_ENDIAN,
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)
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;
636
+ /* revision was hardcoded as 0x91 in original code -- odd */
637
+ s->revision = cpu_class_omap3(mpu) ? SPI_REV_OMAP3430 : SPI_REV_OMAP2420;
641
@@ -362,8 +626,9 @@ struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
644
void omap_mcspi_attach(struct omap_mcspi_s *s,
645
- uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
647
+ uint32_t (*txrx)(void *opaque, uint32_t, int),
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,
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,