]> git.proxmox.com Git - qemu.git/commitdiff
hw: move SSI controllers to hw/ssi/, configure via default-configs/
authorPaolo Bonzini <pbonzini@redhat.com>
Tue, 5 Feb 2013 12:20:08 +0000 (13:20 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Mon, 8 Apr 2013 16:13:13 +0000 (18:13 +0200)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
12 files changed:
default-configs/arm-softmmu.mak
default-configs/microblaze-softmmu.mak
default-configs/microblazeel-softmmu.mak
hw/arm/Makefile.objs
hw/microblaze/Makefile.objs
hw/omap_spi.c [deleted file]
hw/ssi/Makefile.objs
hw/ssi/omap_spi.c [new file with mode: 0644]
hw/ssi/xilinx_spi.c [new file with mode: 0644]
hw/ssi/xilinx_spips.c [new file with mode: 0644]
hw/xilinx_spi.c [deleted file]
hw/xilinx_spips.c [deleted file]

index 24b0d411145f10f1951c6560dcddca06dd2643ec..8eb04e20bf028f743637127159b90e9f007bd7bc 100644 (file)
@@ -52,6 +52,7 @@ CONFIG_EXYNOS4=y
 CONFIG_PXA2XX=y
 CONFIG_BITBANG_I2C=y
 CONFIG_FRAMEBUFFER=y
+CONFIG_XILINX_SPIPS=y
 CONFIG_MARVELL_88W8618=y
 CONFIG_OMAP=y
 CONFIG_BLIZZARD=y
index 050e273580cef4fb1404feb924728cff69388cd2..ce2630818ae511fc883a37798d544c84f08f66cd 100644 (file)
@@ -5,6 +5,7 @@ CONFIG_PFLASH_CFI01=y
 CONFIG_SERIAL=y
 CONFIG_XILINX=y
 CONFIG_XILINX_AXI=y
+CONFIG_XILINX_SPI=y
 CONFIG_XILINX_ETHLITE=y
 CONFIG_SSI=y
 CONFIG_SSI_M25P80=y
index db82dd8086f3607ac4b2549078b600d20ba0b33a..acf22c5bb3175496fc4dcb1596c53212260fcee7 100644 (file)
@@ -5,6 +5,7 @@ CONFIG_PFLASH_CFI01=y
 CONFIG_SERIAL=y
 CONFIG_XILINX=y
 CONFIG_XILINX_AXI=y
+CONFIG_XILINX_SPI=y
 CONFIG_XILINX_ETHLITE=y
 CONFIG_SSI=y
 CONFIG_SSI_M25P80=y
index 45bde589528658befa7a50693f1b49208fe744f6..6f764e62fee6c1c116a62b1d989bdb3ff077d2a9 100644 (file)
@@ -1,5 +1,4 @@
 obj-y += zynq_slcr.o
-obj-y += xilinx_spips.o
 obj-y += arm_gic.o arm_gic_common.o
 obj-y += a9scu.o
 obj-y += realview_gic.o arm_sysctl.o arm11mpcore.o a9mpcore.o
@@ -15,7 +14,7 @@ obj-y += zaurus.o
 obj-y += omap_dma.o omap_clk.o omap_mmc.o \
                 omap_gpio.o omap_intc.o omap_uart.o
 obj-y += soc_dma.o omap_gptimer.o omap_synctimer.o \
-                omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o
+                omap_gpmc.o omap_sdrc.o omap_tap.o omap_l4.o
 obj-y += tsc210x.o
 obj-y += cbus.o tusb6010.o
 obj-y += mst_fpga.o
index 75f5ce6cfe1b87098056a986b6786194e525e795..c65e2aabf1916d7fc3c8a571e25ca707d9f301c4 100644 (file)
@@ -1,7 +1,3 @@
-obj-y += xilinx_spi.o
-
-obj-y := $(addprefix ../,$(obj-y))
-
 obj-y += petalogix_s3adsp1800_mmu.o
 obj-y += petalogix_ml605_mmu.o
 obj-y += boot.o
diff --git a/hw/omap_spi.c b/hw/omap_spi.c
deleted file mode 100644 (file)
index 11403c4..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * TI OMAP processor's Multichannel SPI emulation.
- *
- * Copyright (C) 2007-2009 Nokia Corporation
- *
- * Original code for OMAP2 by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#include "hw/hw.h"
-#include "hw/arm/omap.h"
-
-/* Multichannel SPI */
-struct omap_mcspi_s {
-    MemoryRegion iomem;
-    qemu_irq irq;
-    int chnum;
-
-    uint32_t sysconfig;
-    uint32_t systest;
-    uint32_t irqst;
-    uint32_t irqen;
-    uint32_t wken;
-    uint32_t control;
-
-    struct omap_mcspi_ch_s {
-        qemu_irq txdrq;
-        qemu_irq rxdrq;
-        uint32_t (*txrx)(void *opaque, uint32_t, int);
-        void *opaque;
-
-        uint32_t tx;
-        uint32_t rx;
-
-        uint32_t config;
-        uint32_t status;
-        uint32_t control;
-    } ch[4];
-};
-
-static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s)
-{
-    qemu_set_irq(s->irq, s->irqst & s->irqen);
-}
-
-static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_ch_s *ch)
-{
-    qemu_set_irq(ch->txdrq,
-                    (ch->control & 1) &&               /* EN */
-                    (ch->config & (1 << 14)) &&                /* DMAW */
-                    (ch->status & (1 << 1)) &&         /* TXS */
-                    ((ch->config >> 12) & 3) != 1);    /* TRM */
-    qemu_set_irq(ch->rxdrq,
-                    (ch->control & 1) &&               /* EN */
-                    (ch->config & (1 << 15)) &&                /* DMAW */
-                    (ch->status & (1 << 0)) &&         /* RXS */
-                    ((ch->config >> 12) & 3) != 2);    /* TRM */
-}
-
-static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum)
-{
-    struct omap_mcspi_ch_s *ch = s->ch + chnum;
-
-    if (!(ch->control & 1))                            /* EN */
-        return;
-    if ((ch->status & (1 << 0)) &&                     /* RXS */
-                    ((ch->config >> 12) & 3) != 2 &&   /* TRM */
-                    !(ch->config & (1 << 19)))         /* TURBO */
-        goto intr_update;
-    if ((ch->status & (1 << 1)) &&                     /* TXS */
-                    ((ch->config >> 12) & 3) != 1)     /* TRM */
-        goto intr_update;
-
-    if (!(s->control & 1) ||                           /* SINGLE */
-                    (ch->config & (1 << 20))) {                /* FORCE */
-        if (ch->txrx)
-            ch->rx = ch->txrx(ch->opaque, ch->tx,      /* WL */
-                            1 + (0x1f & (ch->config >> 7)));
-    }
-
-    ch->tx = 0;
-    ch->status |= 1 << 2;                              /* EOT */
-    ch->status |= 1 << 1;                              /* TXS */
-    if (((ch->config >> 12) & 3) != 2)                 /* TRM */
-        ch->status |= 1 << 0;                          /* RXS */
-
-intr_update:
-    if ((ch->status & (1 << 0)) &&                     /* RXS */
-                    ((ch->config >> 12) & 3) != 2 &&   /* TRM */
-                    !(ch->config & (1 << 19)))         /* TURBO */
-        s->irqst |= 1 << (2 + 4 * chnum);              /* RX_FULL */
-    if ((ch->status & (1 << 1)) &&                     /* TXS */
-                    ((ch->config >> 12) & 3) != 1)     /* TRM */
-        s->irqst |= 1 << (0 + 4 * chnum);              /* TX_EMPTY */
-    omap_mcspi_interrupt_update(s);
-    omap_mcspi_dmarequest_update(ch);
-}
-
-void omap_mcspi_reset(struct omap_mcspi_s *s)
-{
-    int ch;
-
-    s->sysconfig = 0;
-    s->systest = 0;
-    s->irqst = 0;
-    s->irqen = 0;
-    s->wken = 0;
-    s->control = 4;
-
-    for (ch = 0; ch < 4; ch ++) {
-        s->ch[ch].config = 0x060000;
-        s->ch[ch].status = 2;                          /* TXS */
-        s->ch[ch].control = 0;
-
-        omap_mcspi_dmarequest_update(s->ch + ch);
-    }
-
-    omap_mcspi_interrupt_update(s);
-}
-
-static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
-                                unsigned size)
-{
-    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
-    int ch = 0;
-    uint32_t ret;
-
-    if (size != 4) {
-        return omap_badwidth_read32(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x00: /* MCSPI_REVISION */
-        return 0x91;
-
-    case 0x10: /* MCSPI_SYSCONFIG */
-        return s->sysconfig;
-
-    case 0x14: /* MCSPI_SYSSTATUS */
-        return 1;                                      /* RESETDONE */
-
-    case 0x18: /* MCSPI_IRQSTATUS */
-        return s->irqst;
-
-    case 0x1c: /* MCSPI_IRQENABLE */
-        return s->irqen;
-
-    case 0x20: /* MCSPI_WAKEUPENABLE */
-        return s->wken;
-
-    case 0x24: /* MCSPI_SYST */
-        return s->systest;
-
-    case 0x28: /* MCSPI_MODULCTRL */
-        return s->control;
-
-    case 0x68: ch ++;
-        /* fall through */
-    case 0x54: ch ++;
-        /* fall through */
-    case 0x40: ch ++;
-        /* fall through */
-    case 0x2c: /* MCSPI_CHCONF */
-        return s->ch[ch].config;
-
-    case 0x6c: ch ++;
-        /* fall through */
-    case 0x58: ch ++;
-        /* fall through */
-    case 0x44: ch ++;
-        /* fall through */
-    case 0x30: /* MCSPI_CHSTAT */
-        return s->ch[ch].status;
-
-    case 0x70: ch ++;
-        /* fall through */
-    case 0x5c: ch ++;
-        /* fall through */
-    case 0x48: ch ++;
-        /* fall through */
-    case 0x34: /* MCSPI_CHCTRL */
-        return s->ch[ch].control;
-
-    case 0x74: ch ++;
-        /* fall through */
-    case 0x60: ch ++;
-        /* fall through */
-    case 0x4c: ch ++;
-        /* fall through */
-    case 0x38: /* MCSPI_TX */
-        return s->ch[ch].tx;
-
-    case 0x78: ch ++;
-        /* fall through */
-    case 0x64: ch ++;
-        /* fall through */
-    case 0x50: ch ++;
-        /* fall through */
-    case 0x3c: /* MCSPI_RX */
-        s->ch[ch].status &= ~(1 << 0);                 /* RXS */
-        ret = s->ch[ch].rx;
-        omap_mcspi_transfer_run(s, ch);
-        return ret;
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_mcspi_write(void *opaque, hwaddr addr,
-                             uint64_t value, unsigned size)
-{
-    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
-    int ch = 0;
-
-    if (size != 4) {
-        return omap_badwidth_write32(opaque, addr, value);
-    }
-
-    switch (addr) {
-    case 0x00: /* MCSPI_REVISION */
-    case 0x14: /* MCSPI_SYSSTATUS */
-    case 0x30: /* MCSPI_CHSTAT0 */
-    case 0x3c: /* MCSPI_RX0 */
-    case 0x44: /* MCSPI_CHSTAT1 */
-    case 0x50: /* MCSPI_RX1 */
-    case 0x58: /* MCSPI_CHSTAT2 */
-    case 0x64: /* MCSPI_RX2 */
-    case 0x6c: /* MCSPI_CHSTAT3 */
-    case 0x78: /* MCSPI_RX3 */
-        OMAP_RO_REG(addr);
-        return;
-
-    case 0x10: /* MCSPI_SYSCONFIG */
-        if (value & (1 << 1))                          /* SOFTRESET */
-            omap_mcspi_reset(s);
-        s->sysconfig = value & 0x31d;
-        break;
-
-    case 0x18: /* MCSPI_IRQSTATUS */
-        if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) {
-            s->irqst &= ~value;
-            omap_mcspi_interrupt_update(s);
-        }
-        break;
-
-    case 0x1c: /* MCSPI_IRQENABLE */
-        s->irqen = value & 0x1777f;
-        omap_mcspi_interrupt_update(s);
-        break;
-
-    case 0x20: /* MCSPI_WAKEUPENABLE */
-        s->wken = value & 1;
-        break;
-
-    case 0x24: /* MCSPI_SYST */
-        if (s->control & (1 << 3))                     /* SYSTEM_TEST */
-            if (value & (1 << 11)) {                   /* SSB */
-                s->irqst |= 0x1777f;
-                omap_mcspi_interrupt_update(s);
-            }
-        s->systest = value & 0xfff;
-        break;
-
-    case 0x28: /* MCSPI_MODULCTRL */
-        if (value & (1 << 3))                          /* SYSTEM_TEST */
-            if (s->systest & (1 << 11)) {              /* SSB */
-                s->irqst |= 0x1777f;
-                omap_mcspi_interrupt_update(s);
-            }
-        s->control = value & 0xf;
-        break;
-
-    case 0x68: ch ++;
-        /* fall through */
-    case 0x54: ch ++;
-        /* fall through */
-    case 0x40: ch ++;
-        /* fall through */
-    case 0x2c: /* MCSPI_CHCONF */
-        if ((value ^ s->ch[ch].config) & (3 << 14))    /* DMAR | DMAW */
-            omap_mcspi_dmarequest_update(s->ch + ch);
-        if (((value >> 12) & 3) == 3)                  /* TRM */
-            fprintf(stderr, "%s: invalid TRM value (3)\n", __FUNCTION__);
-        if (((value >> 7) & 0x1f) < 3)                 /* WL */
-            fprintf(stderr, "%s: invalid WL value (%" PRIx64 ")\n",
-                            __FUNCTION__, (value >> 7) & 0x1f);
-        s->ch[ch].config = value & 0x7fffff;
-        break;
-
-    case 0x70: ch ++;
-        /* fall through */
-    case 0x5c: ch ++;
-        /* fall through */
-    case 0x48: ch ++;
-        /* fall through */
-    case 0x34: /* MCSPI_CHCTRL */
-        if (value & ~s->ch[ch].control & 1) {          /* EN */
-            s->ch[ch].control |= 1;
-            omap_mcspi_transfer_run(s, ch);
-        } else
-            s->ch[ch].control = value & 1;
-        break;
-
-    case 0x74: ch ++;
-        /* fall through */
-    case 0x60: ch ++;
-        /* fall through */
-    case 0x4c: ch ++;
-        /* fall through */
-    case 0x38: /* MCSPI_TX */
-        s->ch[ch].tx = value;
-        s->ch[ch].status &= ~(1 << 1);                 /* TXS */
-        omap_mcspi_transfer_run(s, ch);
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-        return;
-    }
-}
-
-static const MemoryRegionOps omap_mcspi_ops = {
-    .read = omap_mcspi_read,
-    .write = omap_mcspi_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
-                qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
-{
-    struct omap_mcspi_s *s = (struct omap_mcspi_s *)
-            g_malloc0(sizeof(struct omap_mcspi_s));
-    struct omap_mcspi_ch_s *ch = s->ch;
-
-    s->irq = irq;
-    s->chnum = chnum;
-    while (chnum --) {
-        ch->txdrq = *drq ++;
-        ch->rxdrq = *drq ++;
-        ch ++;
-    }
-    omap_mcspi_reset(s);
-
-    memory_region_init_io(&s->iomem, &omap_mcspi_ops, s, "omap.mcspi",
-                          omap_l4_region_size(ta, 0));
-    omap_l4_attach(ta, 0, &s->iomem);
-
-    return s;
-}
-
-void omap_mcspi_attach(struct omap_mcspi_s *s,
-                uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
-                int chipselect)
-{
-    if (chipselect < 0 || chipselect >= s->chnum)
-        hw_error("%s: Bad chipselect %i\n", __FUNCTION__, chipselect);
-
-    s->ch[chipselect].txrx = txrx;
-    s->ch[chipselect].opaque = opaque;
-}
index daada5c66ae2f4b9336555fcc340c937978f0849..9555825acad1c1d2cac869e63210b5d1f171d5a0 100644 (file)
@@ -1,2 +1,6 @@
 common-obj-$(CONFIG_PL022) += pl022.o
 common-obj-$(CONFIG_SSI) += ssi.o
+common-obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
+common-obj-$(CONFIG_XILINX_SPIPS) += xilinx_spips.o
+
+obj-$(CONFIG_OMAP) += omap_spi.o
diff --git a/hw/ssi/omap_spi.c b/hw/ssi/omap_spi.c
new file mode 100644 (file)
index 0000000..11403c4
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * TI OMAP processor's Multichannel SPI emulation.
+ *
+ * Copyright (C) 2007-2009 Nokia Corporation
+ *
+ * Original code for OMAP2 by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "hw/hw.h"
+#include "hw/arm/omap.h"
+
+/* Multichannel SPI */
+struct omap_mcspi_s {
+    MemoryRegion iomem;
+    qemu_irq irq;
+    int chnum;
+
+    uint32_t sysconfig;
+    uint32_t systest;
+    uint32_t irqst;
+    uint32_t irqen;
+    uint32_t wken;
+    uint32_t control;
+
+    struct omap_mcspi_ch_s {
+        qemu_irq txdrq;
+        qemu_irq rxdrq;
+        uint32_t (*txrx)(void *opaque, uint32_t, int);
+        void *opaque;
+
+        uint32_t tx;
+        uint32_t rx;
+
+        uint32_t config;
+        uint32_t status;
+        uint32_t control;
+    } ch[4];
+};
+
+static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s)
+{
+    qemu_set_irq(s->irq, s->irqst & s->irqen);
+}
+
+static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_ch_s *ch)
+{
+    qemu_set_irq(ch->txdrq,
+                    (ch->control & 1) &&               /* EN */
+                    (ch->config & (1 << 14)) &&                /* DMAW */
+                    (ch->status & (1 << 1)) &&         /* TXS */
+                    ((ch->config >> 12) & 3) != 1);    /* TRM */
+    qemu_set_irq(ch->rxdrq,
+                    (ch->control & 1) &&               /* EN */
+                    (ch->config & (1 << 15)) &&                /* DMAW */
+                    (ch->status & (1 << 0)) &&         /* RXS */
+                    ((ch->config >> 12) & 3) != 2);    /* TRM */
+}
+
+static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum)
+{
+    struct omap_mcspi_ch_s *ch = s->ch + chnum;
+
+    if (!(ch->control & 1))                            /* EN */
+        return;
+    if ((ch->status & (1 << 0)) &&                     /* RXS */
+                    ((ch->config >> 12) & 3) != 2 &&   /* TRM */
+                    !(ch->config & (1 << 19)))         /* TURBO */
+        goto intr_update;
+    if ((ch->status & (1 << 1)) &&                     /* TXS */
+                    ((ch->config >> 12) & 3) != 1)     /* TRM */
+        goto intr_update;
+
+    if (!(s->control & 1) ||                           /* SINGLE */
+                    (ch->config & (1 << 20))) {                /* FORCE */
+        if (ch->txrx)
+            ch->rx = ch->txrx(ch->opaque, ch->tx,      /* WL */
+                            1 + (0x1f & (ch->config >> 7)));
+    }
+
+    ch->tx = 0;
+    ch->status |= 1 << 2;                              /* EOT */
+    ch->status |= 1 << 1;                              /* TXS */
+    if (((ch->config >> 12) & 3) != 2)                 /* TRM */
+        ch->status |= 1 << 0;                          /* RXS */
+
+intr_update:
+    if ((ch->status & (1 << 0)) &&                     /* RXS */
+                    ((ch->config >> 12) & 3) != 2 &&   /* TRM */
+                    !(ch->config & (1 << 19)))         /* TURBO */
+        s->irqst |= 1 << (2 + 4 * chnum);              /* RX_FULL */
+    if ((ch->status & (1 << 1)) &&                     /* TXS */
+                    ((ch->config >> 12) & 3) != 1)     /* TRM */
+        s->irqst |= 1 << (0 + 4 * chnum);              /* TX_EMPTY */
+    omap_mcspi_interrupt_update(s);
+    omap_mcspi_dmarequest_update(ch);
+}
+
+void omap_mcspi_reset(struct omap_mcspi_s *s)
+{
+    int ch;
+
+    s->sysconfig = 0;
+    s->systest = 0;
+    s->irqst = 0;
+    s->irqen = 0;
+    s->wken = 0;
+    s->control = 4;
+
+    for (ch = 0; ch < 4; ch ++) {
+        s->ch[ch].config = 0x060000;
+        s->ch[ch].status = 2;                          /* TXS */
+        s->ch[ch].control = 0;
+
+        omap_mcspi_dmarequest_update(s->ch + ch);
+    }
+
+    omap_mcspi_interrupt_update(s);
+}
+
+static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
+                                unsigned size)
+{
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
+    int ch = 0;
+    uint32_t ret;
+
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x00: /* MCSPI_REVISION */
+        return 0x91;
+
+    case 0x10: /* MCSPI_SYSCONFIG */
+        return s->sysconfig;
+
+    case 0x14: /* MCSPI_SYSSTATUS */
+        return 1;                                      /* RESETDONE */
+
+    case 0x18: /* MCSPI_IRQSTATUS */
+        return s->irqst;
+
+    case 0x1c: /* MCSPI_IRQENABLE */
+        return s->irqen;
+
+    case 0x20: /* MCSPI_WAKEUPENABLE */
+        return s->wken;
+
+    case 0x24: /* MCSPI_SYST */
+        return s->systest;
+
+    case 0x28: /* MCSPI_MODULCTRL */
+        return s->control;
+
+    case 0x68: ch ++;
+        /* fall through */
+    case 0x54: ch ++;
+        /* fall through */
+    case 0x40: ch ++;
+        /* fall through */
+    case 0x2c: /* MCSPI_CHCONF */
+        return s->ch[ch].config;
+
+    case 0x6c: ch ++;
+        /* fall through */
+    case 0x58: ch ++;
+        /* fall through */
+    case 0x44: ch ++;
+        /* fall through */
+    case 0x30: /* MCSPI_CHSTAT */
+        return s->ch[ch].status;
+
+    case 0x70: ch ++;
+        /* fall through */
+    case 0x5c: ch ++;
+        /* fall through */
+    case 0x48: ch ++;
+        /* fall through */
+    case 0x34: /* MCSPI_CHCTRL */
+        return s->ch[ch].control;
+
+    case 0x74: ch ++;
+        /* fall through */
+    case 0x60: ch ++;
+        /* fall through */
+    case 0x4c: ch ++;
+        /* fall through */
+    case 0x38: /* MCSPI_TX */
+        return s->ch[ch].tx;
+
+    case 0x78: ch ++;
+        /* fall through */
+    case 0x64: ch ++;
+        /* fall through */
+    case 0x50: ch ++;
+        /* fall through */
+    case 0x3c: /* MCSPI_RX */
+        s->ch[ch].status &= ~(1 << 0);                 /* RXS */
+        ret = s->ch[ch].rx;
+        omap_mcspi_transfer_run(s, ch);
+        return ret;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_mcspi_write(void *opaque, hwaddr addr,
+                             uint64_t value, unsigned size)
+{
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
+    int ch = 0;
+
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
+    switch (addr) {
+    case 0x00: /* MCSPI_REVISION */
+    case 0x14: /* MCSPI_SYSSTATUS */
+    case 0x30: /* MCSPI_CHSTAT0 */
+    case 0x3c: /* MCSPI_RX0 */
+    case 0x44: /* MCSPI_CHSTAT1 */
+    case 0x50: /* MCSPI_RX1 */
+    case 0x58: /* MCSPI_CHSTAT2 */
+    case 0x64: /* MCSPI_RX2 */
+    case 0x6c: /* MCSPI_CHSTAT3 */
+    case 0x78: /* MCSPI_RX3 */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x10: /* MCSPI_SYSCONFIG */
+        if (value & (1 << 1))                          /* SOFTRESET */
+            omap_mcspi_reset(s);
+        s->sysconfig = value & 0x31d;
+        break;
+
+    case 0x18: /* MCSPI_IRQSTATUS */
+        if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) {
+            s->irqst &= ~value;
+            omap_mcspi_interrupt_update(s);
+        }
+        break;
+
+    case 0x1c: /* MCSPI_IRQENABLE */
+        s->irqen = value & 0x1777f;
+        omap_mcspi_interrupt_update(s);
+        break;
+
+    case 0x20: /* MCSPI_WAKEUPENABLE */
+        s->wken = value & 1;
+        break;
+
+    case 0x24: /* MCSPI_SYST */
+        if (s->control & (1 << 3))                     /* SYSTEM_TEST */
+            if (value & (1 << 11)) {                   /* SSB */
+                s->irqst |= 0x1777f;
+                omap_mcspi_interrupt_update(s);
+            }
+        s->systest = value & 0xfff;
+        break;
+
+    case 0x28: /* MCSPI_MODULCTRL */
+        if (value & (1 << 3))                          /* SYSTEM_TEST */
+            if (s->systest & (1 << 11)) {              /* SSB */
+                s->irqst |= 0x1777f;
+                omap_mcspi_interrupt_update(s);
+            }
+        s->control = value & 0xf;
+        break;
+
+    case 0x68: ch ++;
+        /* fall through */
+    case 0x54: ch ++;
+        /* fall through */
+    case 0x40: ch ++;
+        /* fall through */
+    case 0x2c: /* MCSPI_CHCONF */
+        if ((value ^ s->ch[ch].config) & (3 << 14))    /* DMAR | DMAW */
+            omap_mcspi_dmarequest_update(s->ch + ch);
+        if (((value >> 12) & 3) == 3)                  /* TRM */
+            fprintf(stderr, "%s: invalid TRM value (3)\n", __FUNCTION__);
+        if (((value >> 7) & 0x1f) < 3)                 /* WL */
+            fprintf(stderr, "%s: invalid WL value (%" PRIx64 ")\n",
+                            __FUNCTION__, (value >> 7) & 0x1f);
+        s->ch[ch].config = value & 0x7fffff;
+        break;
+
+    case 0x70: ch ++;
+        /* fall through */
+    case 0x5c: ch ++;
+        /* fall through */
+    case 0x48: ch ++;
+        /* fall through */
+    case 0x34: /* MCSPI_CHCTRL */
+        if (value & ~s->ch[ch].control & 1) {          /* EN */
+            s->ch[ch].control |= 1;
+            omap_mcspi_transfer_run(s, ch);
+        } else
+            s->ch[ch].control = value & 1;
+        break;
+
+    case 0x74: ch ++;
+        /* fall through */
+    case 0x60: ch ++;
+        /* fall through */
+    case 0x4c: ch ++;
+        /* fall through */
+    case 0x38: /* MCSPI_TX */
+        s->ch[ch].tx = value;
+        s->ch[ch].status &= ~(1 << 1);                 /* TXS */
+        omap_mcspi_transfer_run(s, ch);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static const MemoryRegionOps omap_mcspi_ops = {
+    .read = omap_mcspi_read,
+    .write = omap_mcspi_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
+                qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
+{
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *)
+            g_malloc0(sizeof(struct omap_mcspi_s));
+    struct omap_mcspi_ch_s *ch = s->ch;
+
+    s->irq = irq;
+    s->chnum = chnum;
+    while (chnum --) {
+        ch->txdrq = *drq ++;
+        ch->rxdrq = *drq ++;
+        ch ++;
+    }
+    omap_mcspi_reset(s);
+
+    memory_region_init_io(&s->iomem, &omap_mcspi_ops, s, "omap.mcspi",
+                          omap_l4_region_size(ta, 0));
+    omap_l4_attach(ta, 0, &s->iomem);
+
+    return s;
+}
+
+void omap_mcspi_attach(struct omap_mcspi_s *s,
+                uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
+                int chipselect)
+{
+    if (chipselect < 0 || chipselect >= s->chnum)
+        hw_error("%s: Bad chipselect %i\n", __FUNCTION__, chipselect);
+
+    s->ch[chipselect].txrx = txrx;
+    s->ch[chipselect].opaque = opaque;
+}
diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c
new file mode 100644 (file)
index 0000000..f6bd3ba
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * QEMU model of the Xilinx SPI Controller
+ *
+ * Copyright (C) 2010 Edgar E. Iglesias.
+ * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
+ * Copyright (C) 2012 PetaLogix
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "qemu/log.h"
+#include "qemu/fifo8.h"
+
+#include "hw/ssi.h"
+
+#ifdef XILINX_SPI_ERR_DEBUG
+#define DB_PRINT(...) do { \
+    fprintf(stderr,  ": %s: ", __func__); \
+    fprintf(stderr, ## __VA_ARGS__); \
+    } while (0);
+#else
+    #define DB_PRINT(...)
+#endif
+
+#define R_DGIER     (0x1c / 4)
+#define R_DGIER_IE  (1 << 31)
+
+#define R_IPISR     (0x20 / 4)
+#define IRQ_DRR_NOT_EMPTY    (1 << (31 - 23))
+#define IRQ_DRR_OVERRUN      (1 << (31 - 26))
+#define IRQ_DRR_FULL         (1 << (31 - 27))
+#define IRQ_TX_FF_HALF_EMPTY (1 << 6)
+#define IRQ_DTR_UNDERRUN     (1 << 3)
+#define IRQ_DTR_EMPTY        (1 << (31 - 29))
+
+#define R_IPIER     (0x28 / 4)
+#define R_SRR       (0x40 / 4)
+#define R_SPICR     (0x60 / 4)
+#define R_SPICR_TXFF_RST     (1 << 5)
+#define R_SPICR_RXFF_RST     (1 << 6)
+#define R_SPICR_MTI          (1 << 8)
+
+#define R_SPISR     (0x64 / 4)
+#define SR_TX_FULL    (1 << 3)
+#define SR_TX_EMPTY   (1 << 2)
+#define SR_RX_FULL    (1 << 1)
+#define SR_RX_EMPTY   (1 << 0)
+
+#define R_SPIDTR    (0x68 / 4)
+#define R_SPIDRR    (0x6C / 4)
+#define R_SPISSR    (0x70 / 4)
+#define R_TX_FF_OCY (0x74 / 4)
+#define R_RX_FF_OCY (0x78 / 4)
+#define R_MAX       (0x7C / 4)
+
+#define FIFO_CAPACITY 256
+
+typedef struct XilinxSPI {
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+
+    qemu_irq irq;
+    int irqline;
+
+    uint8_t num_cs;
+    qemu_irq *cs_lines;
+
+    SSIBus *spi;
+
+    Fifo8 rx_fifo;
+    Fifo8 tx_fifo;
+
+    uint32_t regs[R_MAX];
+} XilinxSPI;
+
+static void txfifo_reset(XilinxSPI *s)
+{
+    fifo8_reset(&s->tx_fifo);
+
+    s->regs[R_SPISR] &= ~SR_TX_FULL;
+    s->regs[R_SPISR] |= SR_TX_EMPTY;
+}
+
+static void rxfifo_reset(XilinxSPI *s)
+{
+    fifo8_reset(&s->rx_fifo);
+
+    s->regs[R_SPISR] |= SR_RX_EMPTY;
+    s->regs[R_SPISR] &= ~SR_RX_FULL;
+}
+
+static void xlx_spi_update_cs(XilinxSPI *s)
+{
+   int i;
+
+    for (i = 0; i < s->num_cs; ++i) {
+        qemu_set_irq(s->cs_lines[i], !(~s->regs[R_SPISSR] & 1 << i));
+    }
+}
+
+static void xlx_spi_update_irq(XilinxSPI *s)
+{
+    uint32_t pending;
+
+    s->regs[R_IPISR] |=
+            (!fifo8_is_empty(&s->rx_fifo) ? IRQ_DRR_NOT_EMPTY : 0) |
+            (fifo8_is_full(&s->rx_fifo) ? IRQ_DRR_FULL : 0);
+
+    pending = s->regs[R_IPISR] & s->regs[R_IPIER];
+
+    pending = pending && (s->regs[R_DGIER] & R_DGIER_IE);
+    pending = !!pending;
+
+    /* This call lies right in the data paths so don't call the
+       irq chain unless things really changed.  */
+    if (pending != s->irqline) {
+        s->irqline = pending;
+        DB_PRINT("irq_change of state %d ISR:%x IER:%X\n",
+                    pending, s->regs[R_IPISR], s->regs[R_IPIER]);
+        qemu_set_irq(s->irq, pending);
+    }
+
+}
+
+static void xlx_spi_do_reset(XilinxSPI *s)
+{
+    memset(s->regs, 0, sizeof s->regs);
+
+    rxfifo_reset(s);
+    txfifo_reset(s);
+
+    s->regs[R_SPISSR] = ~0;
+    xlx_spi_update_irq(s);
+    xlx_spi_update_cs(s);
+}
+
+static void xlx_spi_reset(DeviceState *d)
+{
+    xlx_spi_do_reset(DO_UPCAST(XilinxSPI, busdev.qdev, d));
+}
+
+static inline int spi_master_enabled(XilinxSPI *s)
+{
+    return !(s->regs[R_SPICR] & R_SPICR_MTI);
+}
+
+static void spi_flush_txfifo(XilinxSPI *s)
+{
+    uint32_t tx;
+    uint32_t rx;
+
+    while (!fifo8_is_empty(&s->tx_fifo)) {
+        tx = (uint32_t)fifo8_pop(&s->tx_fifo);
+        DB_PRINT("data tx:%x\n", tx);
+        rx = ssi_transfer(s->spi, tx);
+        DB_PRINT("data rx:%x\n", rx);
+        if (fifo8_is_full(&s->rx_fifo)) {
+            s->regs[R_IPISR] |= IRQ_DRR_OVERRUN;
+        } else {
+            fifo8_push(&s->rx_fifo, (uint8_t)rx);
+            if (fifo8_is_full(&s->rx_fifo)) {
+                s->regs[R_SPISR] |= SR_RX_FULL;
+                s->regs[R_IPISR] |= IRQ_DRR_FULL;
+            }
+        }
+
+        s->regs[R_SPISR] &= ~SR_RX_EMPTY;
+        s->regs[R_SPISR] &= ~SR_TX_FULL;
+        s->regs[R_SPISR] |= SR_TX_EMPTY;
+
+        s->regs[R_IPISR] |= IRQ_DTR_EMPTY;
+        s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY;
+    }
+
+}
+
+static uint64_t
+spi_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    XilinxSPI *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SPIDRR:
+        if (fifo8_is_empty(&s->rx_fifo)) {
+            DB_PRINT("Read from empty FIFO!\n");
+            return 0xdeadbeef;
+        }
+
+        s->regs[R_SPISR] &= ~SR_RX_FULL;
+        r = fifo8_pop(&s->rx_fifo);
+        if (fifo8_is_empty(&s->rx_fifo)) {
+            s->regs[R_SPISR] |= SR_RX_EMPTY;
+        }
+        break;
+
+    case R_SPISR:
+        r = s->regs[addr];
+        break;
+
+    default:
+        if (addr < ARRAY_SIZE(s->regs)) {
+            r = s->regs[addr];
+        }
+        break;
+
+    }
+    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, r);
+    xlx_spi_update_irq(s);
+    return r;
+}
+
+static void
+spi_write(void *opaque, hwaddr addr,
+            uint64_t val64, unsigned int size)
+{
+    XilinxSPI *s = opaque;
+    uint32_t value = val64;
+
+    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, value);
+    addr >>= 2;
+    switch (addr) {
+    case R_SRR:
+        if (value != 0xa) {
+            DB_PRINT("Invalid write to SRR %x\n", value);
+        } else {
+            xlx_spi_do_reset(s);
+        }
+        break;
+
+    case R_SPIDTR:
+        s->regs[R_SPISR] &= ~SR_TX_EMPTY;
+        fifo8_push(&s->tx_fifo, (uint8_t)value);
+        if (fifo8_is_full(&s->tx_fifo)) {
+            s->regs[R_SPISR] |= SR_TX_FULL;
+        }
+        if (!spi_master_enabled(s)) {
+            goto done;
+        } else {
+            DB_PRINT("DTR and master enabled\n");
+        }
+        spi_flush_txfifo(s);
+        break;
+
+    case R_SPISR:
+        DB_PRINT("Invalid write to SPISR %x\n", value);
+        break;
+
+    case R_IPISR:
+        /* Toggle the bits.  */
+        s->regs[addr] ^= value;
+        break;
+
+    /* Slave Select Register.  */
+    case R_SPISSR:
+        s->regs[addr] = value;
+        xlx_spi_update_cs(s);
+        break;
+
+    case R_SPICR:
+        /* FIXME: reset irq and sr state to empty queues.  */
+        if (value & R_SPICR_RXFF_RST) {
+            rxfifo_reset(s);
+        }
+
+        if (value & R_SPICR_TXFF_RST) {
+            txfifo_reset(s);
+        }
+        value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST);
+        s->regs[addr] = value;
+
+        if (!(value & R_SPICR_MTI)) {
+            spi_flush_txfifo(s);
+        }
+        break;
+
+    default:
+        if (addr < ARRAY_SIZE(s->regs)) {
+            s->regs[addr] = value;
+        }
+        break;
+    }
+
+done:
+    xlx_spi_update_irq(s);
+}
+
+static const MemoryRegionOps spi_ops = {
+    .read = spi_read,
+    .write = spi_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static int xilinx_spi_init(SysBusDevice *dev)
+{
+    int i;
+    XilinxSPI *s = FROM_SYSBUS(typeof(*s), dev);
+
+    DB_PRINT("\n");
+
+    s->spi = ssi_create_bus(&dev->qdev, "spi");
+
+    sysbus_init_irq(dev, &s->irq);
+    s->cs_lines = g_new(qemu_irq, s->num_cs);
+    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi);
+    for (i = 0; i < s->num_cs; ++i) {
+        sysbus_init_irq(dev, &s->cs_lines[i]);
+    }
+
+    memory_region_init_io(&s->mmio, &spi_ops, s, "xilinx-spi", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->mmio);
+
+    s->irqline = -1;
+
+    fifo8_create(&s->tx_fifo, FIFO_CAPACITY);
+    fifo8_create(&s->rx_fifo, FIFO_CAPACITY);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_xilinx_spi = {
+    .name = "xilinx_spi",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_FIFO8(tx_fifo, XilinxSPI),
+        VMSTATE_FIFO8(rx_fifo, XilinxSPI),
+        VMSTATE_UINT32_ARRAY(regs, XilinxSPI, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property xilinx_spi_properties[] = {
+    DEFINE_PROP_UINT8("num-ss-bits", XilinxSPI, num_cs, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_spi_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_spi_init;
+    dc->reset = xlx_spi_reset;
+    dc->props = xilinx_spi_properties;
+    dc->vmsd = &vmstate_xilinx_spi;
+}
+
+static const TypeInfo xilinx_spi_info = {
+    .name           = "xlnx.xps-spi",
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(XilinxSPI),
+    .class_init     = xilinx_spi_class_init,
+};
+
+static void xilinx_spi_register_types(void)
+{
+    type_register_static(&xilinx_spi_info);
+}
+
+type_init(xilinx_spi_register_types)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
new file mode 100644 (file)
index 0000000..b2397f4
--- /dev/null
@@ -0,0 +1,595 @@
+/*
+ * QEMU model of the Xilinx Zynq SPI controller
+ *
+ * Copyright (c) 2012 Peter A. G. Crosthwaite
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "hw/ptimer.h"
+#include "qemu/log.h"
+#include "qemu/fifo8.h"
+#include "hw/ssi.h"
+#include "qemu/bitops.h"
+
+#ifdef XILINX_SPIPS_ERR_DEBUG
+#define DB_PRINT(...) do { \
+    fprintf(stderr,  ": %s: ", __func__); \
+    fprintf(stderr, ## __VA_ARGS__); \
+    } while (0);
+#else
+    #define DB_PRINT(...)
+#endif
+
+/* config register */
+#define R_CONFIG            (0x00 / 4)
+#define IFMODE              (1 << 31)
+#define ENDIAN              (1 << 26)
+#define MODEFAIL_GEN_EN     (1 << 17)
+#define MAN_START_COM       (1 << 16)
+#define MAN_START_EN        (1 << 15)
+#define MANUAL_CS           (1 << 14)
+#define CS                  (0xF << 10)
+#define CS_SHIFT            (10)
+#define PERI_SEL            (1 << 9)
+#define REF_CLK             (1 << 8)
+#define FIFO_WIDTH          (3 << 6)
+#define BAUD_RATE_DIV       (7 << 3)
+#define CLK_PH              (1 << 2)
+#define CLK_POL             (1 << 1)
+#define MODE_SEL            (1 << 0)
+
+/* interrupt mechanism */
+#define R_INTR_STATUS       (0x04 / 4)
+#define R_INTR_EN           (0x08 / 4)
+#define R_INTR_DIS          (0x0C / 4)
+#define R_INTR_MASK         (0x10 / 4)
+#define IXR_TX_FIFO_UNDERFLOW   (1 << 6)
+#define IXR_RX_FIFO_FULL        (1 << 5)
+#define IXR_RX_FIFO_NOT_EMPTY   (1 << 4)
+#define IXR_TX_FIFO_FULL        (1 << 3)
+#define IXR_TX_FIFO_NOT_FULL    (1 << 2)
+#define IXR_TX_FIFO_MODE_FAIL   (1 << 1)
+#define IXR_RX_FIFO_OVERFLOW    (1 << 0)
+#define IXR_ALL                 ((IXR_TX_FIFO_UNDERFLOW<<1)-1)
+
+#define R_EN                (0x14 / 4)
+#define R_DELAY             (0x18 / 4)
+#define R_TX_DATA           (0x1C / 4)
+#define R_RX_DATA           (0x20 / 4)
+#define R_SLAVE_IDLE_COUNT  (0x24 / 4)
+#define R_TX_THRES          (0x28 / 4)
+#define R_RX_THRES          (0x2C / 4)
+#define R_TXD1              (0x80 / 4)
+#define R_TXD2              (0x84 / 4)
+#define R_TXD3              (0x88 / 4)
+
+#define R_LQSPI_CFG         (0xa0 / 4)
+#define R_LQSPI_CFG_RESET       0x03A002EB
+#define LQSPI_CFG_LQ_MODE       (1 << 31)
+#define LQSPI_CFG_TWO_MEM       (1 << 30)
+#define LQSPI_CFG_SEP_BUS       (1 << 30)
+#define LQSPI_CFG_U_PAGE        (1 << 28)
+#define LQSPI_CFG_MODE_EN       (1 << 25)
+#define LQSPI_CFG_MODE_WIDTH    8
+#define LQSPI_CFG_MODE_SHIFT    16
+#define LQSPI_CFG_DUMMY_WIDTH   3
+#define LQSPI_CFG_DUMMY_SHIFT   8
+#define LQSPI_CFG_INST_CODE     0xFF
+
+#define R_LQSPI_STS         (0xA4 / 4)
+#define LQSPI_STS_WR_RECVD      (1 << 1)
+
+#define R_MOD_ID            (0xFC / 4)
+
+#define R_MAX (R_MOD_ID+1)
+
+/* size of TXRX FIFOs */
+#define RXFF_A          32
+#define TXFF_A          32
+
+/* 16MB per linear region */
+#define LQSPI_ADDRESS_BITS 24
+/* Bite off 4k chunks at a time */
+#define LQSPI_CACHE_SIZE 1024
+
+#define SNOOP_CHECKING 0xFF
+#define SNOOP_NONE 0xFE
+#define SNOOP_STRIPING 0
+
+typedef enum {
+    READ = 0x3,
+    FAST_READ = 0xb,
+    DOR = 0x3b,
+    QOR = 0x6b,
+    DIOR = 0xbb,
+    QIOR = 0xeb,
+
+    PP = 0x2,
+    DPP = 0xa2,
+    QPP = 0x32,
+} FlashCMD;
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    MemoryRegion mmlqspi;
+
+    qemu_irq irq;
+    int irqline;
+
+    uint8_t num_cs;
+    uint8_t num_busses;
+
+    uint8_t snoop_state;
+    qemu_irq *cs_lines;
+    SSIBus **spi;
+
+    Fifo8 rx_fifo;
+    Fifo8 tx_fifo;
+
+    uint8_t num_txrx_bytes;
+
+    uint32_t regs[R_MAX];
+
+    uint32_t lqspi_buf[LQSPI_CACHE_SIZE];
+    hwaddr lqspi_cached_addr;
+} XilinxSPIPS;
+
+#define TYPE_XILINX_SPIPS "xilinx,spips"
+
+#define XILINX_SPIPS(obj) \
+     OBJECT_CHECK(XilinxSPIPS, (obj), TYPE_XILINX_SPIPS)
+
+static inline int num_effective_busses(XilinxSPIPS *s)
+{
+    return (s->regs[R_LQSPI_CFG] & LQSPI_CFG_SEP_BUS &&
+            s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1;
+}
+
+static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
+{
+    int i, j;
+    bool found = false;
+    int field = s->regs[R_CONFIG] >> CS_SHIFT;
+
+    for (i = 0; i < s->num_cs; i++) {
+        for (j = 0; j < num_effective_busses(s); j++) {
+            int upage = !!(s->regs[R_LQSPI_STS] & LQSPI_CFG_U_PAGE);
+            int cs_to_set = (j * s->num_cs + i + upage) %
+                                (s->num_cs * s->num_busses);
+
+            if (~field & (1 << i) && !found) {
+                DB_PRINT("selecting slave %d\n", i);
+                qemu_set_irq(s->cs_lines[cs_to_set], 0);
+            } else {
+                qemu_set_irq(s->cs_lines[cs_to_set], 1);
+            }
+        }
+        if (~field & (1 << i)) {
+            found = true;
+        }
+    }
+    if (!found) {
+        s->snoop_state = SNOOP_CHECKING;
+    }
+}
+
+static void xilinx_spips_update_ixr(XilinxSPIPS *s)
+{
+    /* These are set/cleared as they occur */
+    s->regs[R_INTR_STATUS] &= (IXR_TX_FIFO_UNDERFLOW | IXR_RX_FIFO_OVERFLOW |
+                                IXR_TX_FIFO_MODE_FAIL);
+    /* these are pure functions of fifo state, set them here */
+    s->regs[R_INTR_STATUS] |=
+        (fifo8_is_full(&s->rx_fifo) ? IXR_RX_FIFO_FULL : 0) |
+        (s->rx_fifo.num >= s->regs[R_RX_THRES] ? IXR_RX_FIFO_NOT_EMPTY : 0) |
+        (fifo8_is_full(&s->tx_fifo) ? IXR_TX_FIFO_FULL : 0) |
+        (s->tx_fifo.num < s->regs[R_TX_THRES] ? IXR_TX_FIFO_NOT_FULL : 0);
+    /* drive external interrupt pin */
+    int new_irqline = !!(s->regs[R_INTR_MASK] & s->regs[R_INTR_STATUS] &
+                                                                IXR_ALL);
+    if (new_irqline != s->irqline) {
+        s->irqline = new_irqline;
+        qemu_set_irq(s->irq, s->irqline);
+    }
+}
+
+static void xilinx_spips_reset(DeviceState *d)
+{
+    XilinxSPIPS *s = XILINX_SPIPS(d);
+
+    int i;
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    fifo8_reset(&s->rx_fifo);
+    fifo8_reset(&s->rx_fifo);
+    /* non zero resets */
+    s->regs[R_CONFIG] |= MODEFAIL_GEN_EN;
+    s->regs[R_SLAVE_IDLE_COUNT] = 0xFF;
+    s->regs[R_TX_THRES] = 1;
+    s->regs[R_RX_THRES] = 1;
+    /* FIXME: move magic number definition somewhere sensible */
+    s->regs[R_MOD_ID] = 0x01090106;
+    s->regs[R_LQSPI_CFG] = R_LQSPI_CFG_RESET;
+    s->snoop_state = SNOOP_CHECKING;
+    xilinx_spips_update_ixr(s);
+    xilinx_spips_update_cs_lines(s);
+}
+
+static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
+{
+    for (;;) {
+        int i;
+        uint8_t rx;
+        uint8_t tx = 0;
+
+        for (i = 0; i < num_effective_busses(s); ++i) {
+            if (!i || s->snoop_state == SNOOP_STRIPING) {
+                if (fifo8_is_empty(&s->tx_fifo)) {
+                    s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW;
+                    xilinx_spips_update_ixr(s);
+                    return;
+                } else {
+                    tx = fifo8_pop(&s->tx_fifo);
+                }
+            }
+            rx = ssi_transfer(s->spi[i], (uint32_t)tx);
+            DB_PRINT("tx = %02x rx = %02x\n", tx, rx);
+            if (!i || s->snoop_state == SNOOP_STRIPING) {
+                if (fifo8_is_full(&s->rx_fifo)) {
+                    s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW;
+                    DB_PRINT("rx FIFO overflow");
+                } else {
+                    fifo8_push(&s->rx_fifo, (uint8_t)rx);
+                }
+            }
+        }
+
+        switch (s->snoop_state) {
+        case (SNOOP_CHECKING):
+            switch (tx) { /* new instruction code */
+            case READ: /* 3 address bytes, no dummy bytes/cycles */
+            case PP:
+            case DPP:
+            case QPP:
+                s->snoop_state = 3;
+                break;
+            case FAST_READ: /* 3 address bytes, 1 dummy byte */
+            case DOR:
+            case QOR:
+            case DIOR: /* FIXME: these vary between vendor - set to spansion */
+                s->snoop_state = 4;
+                break;
+            case QIOR: /* 3 address bytes, 2 dummy bytes */
+                s->snoop_state = 6;
+                break;
+            default:
+                s->snoop_state = SNOOP_NONE;
+            }
+            break;
+        case (SNOOP_STRIPING):
+        case (SNOOP_NONE):
+            break;
+        default:
+            s->snoop_state--;
+        }
+    }
+}
+
+static inline void rx_data_bytes(XilinxSPIPS *s, uint32_t *value, int max)
+{
+    int i;
+
+    *value = 0;
+    for (i = 0; i < max && !fifo8_is_empty(&s->rx_fifo); ++i) {
+        uint32_t next = fifo8_pop(&s->rx_fifo) & 0xFF;
+        *value |= next << 8 * (s->regs[R_CONFIG] & ENDIAN ? 3-i : i);
+    }
+}
+
+static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
+                                                        unsigned size)
+{
+    XilinxSPIPS *s = opaque;
+    uint32_t mask = ~0;
+    uint32_t ret;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CONFIG:
+        mask = 0x0002FFFF;
+        break;
+    case R_INTR_STATUS:
+    case R_INTR_MASK:
+        mask = IXR_ALL;
+        break;
+    case  R_EN:
+        mask = 0x1;
+        break;
+    case R_SLAVE_IDLE_COUNT:
+        mask = 0xFF;
+        break;
+    case R_MOD_ID:
+        mask = 0x01FFFFFF;
+        break;
+    case R_INTR_EN:
+    case R_INTR_DIS:
+    case R_TX_DATA:
+        mask = 0;
+        break;
+    case R_RX_DATA:
+        rx_data_bytes(s, &ret, s->num_txrx_bytes);
+        DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
+        xilinx_spips_update_ixr(s);
+        return ret;
+    }
+    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, s->regs[addr] & mask);
+    return s->regs[addr] & mask;
+
+}
+
+static inline void tx_data_bytes(XilinxSPIPS *s, uint32_t value, int num)
+{
+    int i;
+    for (i = 0; i < num && !fifo8_is_full(&s->tx_fifo); ++i) {
+        if (s->regs[R_CONFIG] & ENDIAN) {
+            fifo8_push(&s->tx_fifo, (uint8_t)(value >> 24));
+            value <<= 8;
+        } else {
+            fifo8_push(&s->tx_fifo, (uint8_t)value);
+            value >>= 8;
+        }
+    }
+}
+
+static void xilinx_spips_write(void *opaque, hwaddr addr,
+                                        uint64_t value, unsigned size)
+{
+    int mask = ~0;
+    int man_start_com = 0;
+    XilinxSPIPS *s = opaque;
+
+    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value);
+    addr >>= 2;
+    switch (addr) {
+    case R_CONFIG:
+        mask = 0x0002FFFF;
+        if (value & MAN_START_COM) {
+            man_start_com = 1;
+        }
+        break;
+    case R_INTR_STATUS:
+        mask = IXR_ALL;
+        s->regs[R_INTR_STATUS] &= ~(mask & value);
+        goto no_reg_update;
+    case R_INTR_DIS:
+        mask = IXR_ALL;
+        s->regs[R_INTR_MASK] &= ~(mask & value);
+        goto no_reg_update;
+    case R_INTR_EN:
+        mask = IXR_ALL;
+        s->regs[R_INTR_MASK] |= mask & value;
+        goto no_reg_update;
+    case R_EN:
+        mask = 0x1;
+        break;
+    case R_SLAVE_IDLE_COUNT:
+        mask = 0xFF;
+        break;
+    case R_RX_DATA:
+    case R_INTR_MASK:
+    case R_MOD_ID:
+        mask = 0;
+        break;
+    case R_TX_DATA:
+        tx_data_bytes(s, (uint32_t)value, s->num_txrx_bytes);
+        goto no_reg_update;
+    case R_TXD1:
+        tx_data_bytes(s, (uint32_t)value, 1);
+        goto no_reg_update;
+    case R_TXD2:
+        tx_data_bytes(s, (uint32_t)value, 2);
+        goto no_reg_update;
+    case R_TXD3:
+        tx_data_bytes(s, (uint32_t)value, 3);
+        goto no_reg_update;
+    }
+    s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask);
+no_reg_update:
+    if (man_start_com) {
+        xilinx_spips_flush_txfifo(s);
+    }
+    xilinx_spips_update_ixr(s);
+    xilinx_spips_update_cs_lines(s);
+}
+
+static const MemoryRegionOps spips_ops = {
+    .read = xilinx_spips_read,
+    .write = xilinx_spips_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+#define LQSPI_CACHE_SIZE 1024
+
+static uint64_t
+lqspi_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    int i;
+    XilinxSPIPS *s = opaque;
+
+    if (addr >= s->lqspi_cached_addr &&
+            addr <= s->lqspi_cached_addr + LQSPI_CACHE_SIZE - 4) {
+        return s->lqspi_buf[(addr - s->lqspi_cached_addr) >> 2];
+    } else {
+        int flash_addr = (addr / num_effective_busses(s));
+        int slave = flash_addr >> LQSPI_ADDRESS_BITS;
+        int cache_entry = 0;
+
+        DB_PRINT("config reg status: %08x\n", s->regs[R_LQSPI_CFG]);
+
+        fifo8_reset(&s->tx_fifo);
+        fifo8_reset(&s->rx_fifo);
+
+        s->regs[R_CONFIG] &= ~CS;
+        s->regs[R_CONFIG] |= (~(1 << slave) << CS_SHIFT) & CS;
+        xilinx_spips_update_cs_lines(s);
+
+        /* instruction */
+        DB_PRINT("pushing read instruction: %02x\n",
+                 (uint8_t)(s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE));
+        fifo8_push(&s->tx_fifo, s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE);
+        /* read address */
+        DB_PRINT("pushing read address %06x\n", flash_addr);
+        fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 16));
+        fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 8));
+        fifo8_push(&s->tx_fifo, (uint8_t)flash_addr);
+        /* mode bits */
+        if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_MODE_EN) {
+            fifo8_push(&s->tx_fifo, extract32(s->regs[R_LQSPI_CFG],
+                                              LQSPI_CFG_MODE_SHIFT,
+                                              LQSPI_CFG_MODE_WIDTH));
+        }
+        /* dummy bytes */
+        for (i = 0; i < (extract32(s->regs[R_LQSPI_CFG], LQSPI_CFG_DUMMY_SHIFT,
+                                   LQSPI_CFG_DUMMY_WIDTH)); ++i) {
+            DB_PRINT("pushing dummy byte\n");
+            fifo8_push(&s->tx_fifo, 0);
+        }
+        xilinx_spips_flush_txfifo(s);
+        fifo8_reset(&s->rx_fifo);
+
+        DB_PRINT("starting QSPI data read\n");
+
+        for (i = 0; i < LQSPI_CACHE_SIZE / 4; ++i) {
+            tx_data_bytes(s, 0, 4);
+            xilinx_spips_flush_txfifo(s);
+            rx_data_bytes(s, &s->lqspi_buf[cache_entry], 4);
+            cache_entry++;
+        }
+
+        s->regs[R_CONFIG] |= CS;
+        xilinx_spips_update_cs_lines(s);
+
+        s->lqspi_cached_addr = addr;
+        return lqspi_read(opaque, addr, size);
+    }
+}
+
+static const MemoryRegionOps lqspi_ops = {
+    .read = lqspi_read,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void xilinx_spips_realize(DeviceState *dev, Error **errp)
+{
+    XilinxSPIPS *s = XILINX_SPIPS(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    int i;
+
+    DB_PRINT("inited device model\n");
+
+    s->spi = g_new(SSIBus *, s->num_busses);
+    for (i = 0; i < s->num_busses; ++i) {
+        char bus_name[16];
+        snprintf(bus_name, 16, "spi%d", i);
+        s->spi[i] = ssi_create_bus(dev, bus_name);
+    }
+
+    s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses);
+    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[0]);
+    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[1]);
+    sysbus_init_irq(sbd, &s->irq);
+    for (i = 0; i < s->num_cs * s->num_busses; ++i) {
+        sysbus_init_irq(sbd, &s->cs_lines[i]);
+    }
+
+    memory_region_init_io(&s->iomem, &spips_ops, s, "spi", R_MAX*4);
+    sysbus_init_mmio(sbd, &s->iomem);
+
+    memory_region_init_io(&s->mmlqspi, &lqspi_ops, s, "lqspi",
+                          (1 << LQSPI_ADDRESS_BITS) * 2);
+    sysbus_init_mmio(sbd, &s->mmlqspi);
+
+    s->irqline = -1;
+    s->lqspi_cached_addr = ~0ULL;
+
+    fifo8_create(&s->rx_fifo, RXFF_A);
+    fifo8_create(&s->tx_fifo, TXFF_A);
+}
+
+static int xilinx_spips_post_load(void *opaque, int version_id)
+{
+    xilinx_spips_update_ixr((XilinxSPIPS *)opaque);
+    xilinx_spips_update_cs_lines((XilinxSPIPS *)opaque);
+    return 0;
+}
+
+static const VMStateDescription vmstate_xilinx_spips = {
+    .name = "xilinx_spips",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .post_load = xilinx_spips_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_FIFO8(tx_fifo, XilinxSPIPS),
+        VMSTATE_FIFO8(rx_fifo, XilinxSPIPS),
+        VMSTATE_UINT32_ARRAY(regs, XilinxSPIPS, R_MAX),
+        VMSTATE_UINT8(snoop_state, XilinxSPIPS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property xilinx_spips_properties[] = {
+    DEFINE_PROP_UINT8("num-busses", XilinxSPIPS, num_busses, 1),
+    DEFINE_PROP_UINT8("num-ss-bits", XilinxSPIPS, num_cs, 4),
+    DEFINE_PROP_UINT8("num-txrx-bytes", XilinxSPIPS, num_txrx_bytes, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+static void xilinx_spips_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = xilinx_spips_realize;
+    dc->reset = xilinx_spips_reset;
+    dc->props = xilinx_spips_properties;
+    dc->vmsd = &vmstate_xilinx_spips;
+}
+
+static const TypeInfo xilinx_spips_info = {
+    .name  = TYPE_XILINX_SPIPS,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(XilinxSPIPS),
+    .class_init = xilinx_spips_class_init,
+};
+
+static void xilinx_spips_register_types(void)
+{
+    type_register_static(&xilinx_spips_info);
+}
+
+type_init(xilinx_spips_register_types)
diff --git a/hw/xilinx_spi.c b/hw/xilinx_spi.c
deleted file mode 100644 (file)
index f6bd3ba..0000000
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * QEMU model of the Xilinx SPI Controller
- *
- * Copyright (C) 2010 Edgar E. Iglesias.
- * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
- * Copyright (C) 2012 PetaLogix
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "qemu/log.h"
-#include "qemu/fifo8.h"
-
-#include "hw/ssi.h"
-
-#ifdef XILINX_SPI_ERR_DEBUG
-#define DB_PRINT(...) do { \
-    fprintf(stderr,  ": %s: ", __func__); \
-    fprintf(stderr, ## __VA_ARGS__); \
-    } while (0);
-#else
-    #define DB_PRINT(...)
-#endif
-
-#define R_DGIER     (0x1c / 4)
-#define R_DGIER_IE  (1 << 31)
-
-#define R_IPISR     (0x20 / 4)
-#define IRQ_DRR_NOT_EMPTY    (1 << (31 - 23))
-#define IRQ_DRR_OVERRUN      (1 << (31 - 26))
-#define IRQ_DRR_FULL         (1 << (31 - 27))
-#define IRQ_TX_FF_HALF_EMPTY (1 << 6)
-#define IRQ_DTR_UNDERRUN     (1 << 3)
-#define IRQ_DTR_EMPTY        (1 << (31 - 29))
-
-#define R_IPIER     (0x28 / 4)
-#define R_SRR       (0x40 / 4)
-#define R_SPICR     (0x60 / 4)
-#define R_SPICR_TXFF_RST     (1 << 5)
-#define R_SPICR_RXFF_RST     (1 << 6)
-#define R_SPICR_MTI          (1 << 8)
-
-#define R_SPISR     (0x64 / 4)
-#define SR_TX_FULL    (1 << 3)
-#define SR_TX_EMPTY   (1 << 2)
-#define SR_RX_FULL    (1 << 1)
-#define SR_RX_EMPTY   (1 << 0)
-
-#define R_SPIDTR    (0x68 / 4)
-#define R_SPIDRR    (0x6C / 4)
-#define R_SPISSR    (0x70 / 4)
-#define R_TX_FF_OCY (0x74 / 4)
-#define R_RX_FF_OCY (0x78 / 4)
-#define R_MAX       (0x7C / 4)
-
-#define FIFO_CAPACITY 256
-
-typedef struct XilinxSPI {
-    SysBusDevice busdev;
-    MemoryRegion mmio;
-
-    qemu_irq irq;
-    int irqline;
-
-    uint8_t num_cs;
-    qemu_irq *cs_lines;
-
-    SSIBus *spi;
-
-    Fifo8 rx_fifo;
-    Fifo8 tx_fifo;
-
-    uint32_t regs[R_MAX];
-} XilinxSPI;
-
-static void txfifo_reset(XilinxSPI *s)
-{
-    fifo8_reset(&s->tx_fifo);
-
-    s->regs[R_SPISR] &= ~SR_TX_FULL;
-    s->regs[R_SPISR] |= SR_TX_EMPTY;
-}
-
-static void rxfifo_reset(XilinxSPI *s)
-{
-    fifo8_reset(&s->rx_fifo);
-
-    s->regs[R_SPISR] |= SR_RX_EMPTY;
-    s->regs[R_SPISR] &= ~SR_RX_FULL;
-}
-
-static void xlx_spi_update_cs(XilinxSPI *s)
-{
-   int i;
-
-    for (i = 0; i < s->num_cs; ++i) {
-        qemu_set_irq(s->cs_lines[i], !(~s->regs[R_SPISSR] & 1 << i));
-    }
-}
-
-static void xlx_spi_update_irq(XilinxSPI *s)
-{
-    uint32_t pending;
-
-    s->regs[R_IPISR] |=
-            (!fifo8_is_empty(&s->rx_fifo) ? IRQ_DRR_NOT_EMPTY : 0) |
-            (fifo8_is_full(&s->rx_fifo) ? IRQ_DRR_FULL : 0);
-
-    pending = s->regs[R_IPISR] & s->regs[R_IPIER];
-
-    pending = pending && (s->regs[R_DGIER] & R_DGIER_IE);
-    pending = !!pending;
-
-    /* This call lies right in the data paths so don't call the
-       irq chain unless things really changed.  */
-    if (pending != s->irqline) {
-        s->irqline = pending;
-        DB_PRINT("irq_change of state %d ISR:%x IER:%X\n",
-                    pending, s->regs[R_IPISR], s->regs[R_IPIER]);
-        qemu_set_irq(s->irq, pending);
-    }
-
-}
-
-static void xlx_spi_do_reset(XilinxSPI *s)
-{
-    memset(s->regs, 0, sizeof s->regs);
-
-    rxfifo_reset(s);
-    txfifo_reset(s);
-
-    s->regs[R_SPISSR] = ~0;
-    xlx_spi_update_irq(s);
-    xlx_spi_update_cs(s);
-}
-
-static void xlx_spi_reset(DeviceState *d)
-{
-    xlx_spi_do_reset(DO_UPCAST(XilinxSPI, busdev.qdev, d));
-}
-
-static inline int spi_master_enabled(XilinxSPI *s)
-{
-    return !(s->regs[R_SPICR] & R_SPICR_MTI);
-}
-
-static void spi_flush_txfifo(XilinxSPI *s)
-{
-    uint32_t tx;
-    uint32_t rx;
-
-    while (!fifo8_is_empty(&s->tx_fifo)) {
-        tx = (uint32_t)fifo8_pop(&s->tx_fifo);
-        DB_PRINT("data tx:%x\n", tx);
-        rx = ssi_transfer(s->spi, tx);
-        DB_PRINT("data rx:%x\n", rx);
-        if (fifo8_is_full(&s->rx_fifo)) {
-            s->regs[R_IPISR] |= IRQ_DRR_OVERRUN;
-        } else {
-            fifo8_push(&s->rx_fifo, (uint8_t)rx);
-            if (fifo8_is_full(&s->rx_fifo)) {
-                s->regs[R_SPISR] |= SR_RX_FULL;
-                s->regs[R_IPISR] |= IRQ_DRR_FULL;
-            }
-        }
-
-        s->regs[R_SPISR] &= ~SR_RX_EMPTY;
-        s->regs[R_SPISR] &= ~SR_TX_FULL;
-        s->regs[R_SPISR] |= SR_TX_EMPTY;
-
-        s->regs[R_IPISR] |= IRQ_DTR_EMPTY;
-        s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY;
-    }
-
-}
-
-static uint64_t
-spi_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    XilinxSPI *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_SPIDRR:
-        if (fifo8_is_empty(&s->rx_fifo)) {
-            DB_PRINT("Read from empty FIFO!\n");
-            return 0xdeadbeef;
-        }
-
-        s->regs[R_SPISR] &= ~SR_RX_FULL;
-        r = fifo8_pop(&s->rx_fifo);
-        if (fifo8_is_empty(&s->rx_fifo)) {
-            s->regs[R_SPISR] |= SR_RX_EMPTY;
-        }
-        break;
-
-    case R_SPISR:
-        r = s->regs[addr];
-        break;
-
-    default:
-        if (addr < ARRAY_SIZE(s->regs)) {
-            r = s->regs[addr];
-        }
-        break;
-
-    }
-    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, r);
-    xlx_spi_update_irq(s);
-    return r;
-}
-
-static void
-spi_write(void *opaque, hwaddr addr,
-            uint64_t val64, unsigned int size)
-{
-    XilinxSPI *s = opaque;
-    uint32_t value = val64;
-
-    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, value);
-    addr >>= 2;
-    switch (addr) {
-    case R_SRR:
-        if (value != 0xa) {
-            DB_PRINT("Invalid write to SRR %x\n", value);
-        } else {
-            xlx_spi_do_reset(s);
-        }
-        break;
-
-    case R_SPIDTR:
-        s->regs[R_SPISR] &= ~SR_TX_EMPTY;
-        fifo8_push(&s->tx_fifo, (uint8_t)value);
-        if (fifo8_is_full(&s->tx_fifo)) {
-            s->regs[R_SPISR] |= SR_TX_FULL;
-        }
-        if (!spi_master_enabled(s)) {
-            goto done;
-        } else {
-            DB_PRINT("DTR and master enabled\n");
-        }
-        spi_flush_txfifo(s);
-        break;
-
-    case R_SPISR:
-        DB_PRINT("Invalid write to SPISR %x\n", value);
-        break;
-
-    case R_IPISR:
-        /* Toggle the bits.  */
-        s->regs[addr] ^= value;
-        break;
-
-    /* Slave Select Register.  */
-    case R_SPISSR:
-        s->regs[addr] = value;
-        xlx_spi_update_cs(s);
-        break;
-
-    case R_SPICR:
-        /* FIXME: reset irq and sr state to empty queues.  */
-        if (value & R_SPICR_RXFF_RST) {
-            rxfifo_reset(s);
-        }
-
-        if (value & R_SPICR_TXFF_RST) {
-            txfifo_reset(s);
-        }
-        value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST);
-        s->regs[addr] = value;
-
-        if (!(value & R_SPICR_MTI)) {
-            spi_flush_txfifo(s);
-        }
-        break;
-
-    default:
-        if (addr < ARRAY_SIZE(s->regs)) {
-            s->regs[addr] = value;
-        }
-        break;
-    }
-
-done:
-    xlx_spi_update_irq(s);
-}
-
-static const MemoryRegionOps spi_ops = {
-    .read = spi_read,
-    .write = spi_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static int xilinx_spi_init(SysBusDevice *dev)
-{
-    int i;
-    XilinxSPI *s = FROM_SYSBUS(typeof(*s), dev);
-
-    DB_PRINT("\n");
-
-    s->spi = ssi_create_bus(&dev->qdev, "spi");
-
-    sysbus_init_irq(dev, &s->irq);
-    s->cs_lines = g_new(qemu_irq, s->num_cs);
-    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi);
-    for (i = 0; i < s->num_cs; ++i) {
-        sysbus_init_irq(dev, &s->cs_lines[i]);
-    }
-
-    memory_region_init_io(&s->mmio, &spi_ops, s, "xilinx-spi", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->mmio);
-
-    s->irqline = -1;
-
-    fifo8_create(&s->tx_fifo, FIFO_CAPACITY);
-    fifo8_create(&s->rx_fifo, FIFO_CAPACITY);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_xilinx_spi = {
-    .name = "xilinx_spi",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_FIFO8(tx_fifo, XilinxSPI),
-        VMSTATE_FIFO8(rx_fifo, XilinxSPI),
-        VMSTATE_UINT32_ARRAY(regs, XilinxSPI, R_MAX),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property xilinx_spi_properties[] = {
-    DEFINE_PROP_UINT8("num-ss-bits", XilinxSPI, num_cs, 1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xilinx_spi_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = xilinx_spi_init;
-    dc->reset = xlx_spi_reset;
-    dc->props = xilinx_spi_properties;
-    dc->vmsd = &vmstate_xilinx_spi;
-}
-
-static const TypeInfo xilinx_spi_info = {
-    .name           = "xlnx.xps-spi",
-    .parent         = TYPE_SYS_BUS_DEVICE,
-    .instance_size  = sizeof(XilinxSPI),
-    .class_init     = xilinx_spi_class_init,
-};
-
-static void xilinx_spi_register_types(void)
-{
-    type_register_static(&xilinx_spi_info);
-}
-
-type_init(xilinx_spi_register_types)
diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c
deleted file mode 100644 (file)
index b2397f4..0000000
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * QEMU model of the Xilinx Zynq SPI controller
- *
- * Copyright (c) 2012 Peter A. G. Crosthwaite
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "hw/ptimer.h"
-#include "qemu/log.h"
-#include "qemu/fifo8.h"
-#include "hw/ssi.h"
-#include "qemu/bitops.h"
-
-#ifdef XILINX_SPIPS_ERR_DEBUG
-#define DB_PRINT(...) do { \
-    fprintf(stderr,  ": %s: ", __func__); \
-    fprintf(stderr, ## __VA_ARGS__); \
-    } while (0);
-#else
-    #define DB_PRINT(...)
-#endif
-
-/* config register */
-#define R_CONFIG            (0x00 / 4)
-#define IFMODE              (1 << 31)
-#define ENDIAN              (1 << 26)
-#define MODEFAIL_GEN_EN     (1 << 17)
-#define MAN_START_COM       (1 << 16)
-#define MAN_START_EN        (1 << 15)
-#define MANUAL_CS           (1 << 14)
-#define CS                  (0xF << 10)
-#define CS_SHIFT            (10)
-#define PERI_SEL            (1 << 9)
-#define REF_CLK             (1 << 8)
-#define FIFO_WIDTH          (3 << 6)
-#define BAUD_RATE_DIV       (7 << 3)
-#define CLK_PH              (1 << 2)
-#define CLK_POL             (1 << 1)
-#define MODE_SEL            (1 << 0)
-
-/* interrupt mechanism */
-#define R_INTR_STATUS       (0x04 / 4)
-#define R_INTR_EN           (0x08 / 4)
-#define R_INTR_DIS          (0x0C / 4)
-#define R_INTR_MASK         (0x10 / 4)
-#define IXR_TX_FIFO_UNDERFLOW   (1 << 6)
-#define IXR_RX_FIFO_FULL        (1 << 5)
-#define IXR_RX_FIFO_NOT_EMPTY   (1 << 4)
-#define IXR_TX_FIFO_FULL        (1 << 3)
-#define IXR_TX_FIFO_NOT_FULL    (1 << 2)
-#define IXR_TX_FIFO_MODE_FAIL   (1 << 1)
-#define IXR_RX_FIFO_OVERFLOW    (1 << 0)
-#define IXR_ALL                 ((IXR_TX_FIFO_UNDERFLOW<<1)-1)
-
-#define R_EN                (0x14 / 4)
-#define R_DELAY             (0x18 / 4)
-#define R_TX_DATA           (0x1C / 4)
-#define R_RX_DATA           (0x20 / 4)
-#define R_SLAVE_IDLE_COUNT  (0x24 / 4)
-#define R_TX_THRES          (0x28 / 4)
-#define R_RX_THRES          (0x2C / 4)
-#define R_TXD1              (0x80 / 4)
-#define R_TXD2              (0x84 / 4)
-#define R_TXD3              (0x88 / 4)
-
-#define R_LQSPI_CFG         (0xa0 / 4)
-#define R_LQSPI_CFG_RESET       0x03A002EB
-#define LQSPI_CFG_LQ_MODE       (1 << 31)
-#define LQSPI_CFG_TWO_MEM       (1 << 30)
-#define LQSPI_CFG_SEP_BUS       (1 << 30)
-#define LQSPI_CFG_U_PAGE        (1 << 28)
-#define LQSPI_CFG_MODE_EN       (1 << 25)
-#define LQSPI_CFG_MODE_WIDTH    8
-#define LQSPI_CFG_MODE_SHIFT    16
-#define LQSPI_CFG_DUMMY_WIDTH   3
-#define LQSPI_CFG_DUMMY_SHIFT   8
-#define LQSPI_CFG_INST_CODE     0xFF
-
-#define R_LQSPI_STS         (0xA4 / 4)
-#define LQSPI_STS_WR_RECVD      (1 << 1)
-
-#define R_MOD_ID            (0xFC / 4)
-
-#define R_MAX (R_MOD_ID+1)
-
-/* size of TXRX FIFOs */
-#define RXFF_A          32
-#define TXFF_A          32
-
-/* 16MB per linear region */
-#define LQSPI_ADDRESS_BITS 24
-/* Bite off 4k chunks at a time */
-#define LQSPI_CACHE_SIZE 1024
-
-#define SNOOP_CHECKING 0xFF
-#define SNOOP_NONE 0xFE
-#define SNOOP_STRIPING 0
-
-typedef enum {
-    READ = 0x3,
-    FAST_READ = 0xb,
-    DOR = 0x3b,
-    QOR = 0x6b,
-    DIOR = 0xbb,
-    QIOR = 0xeb,
-
-    PP = 0x2,
-    DPP = 0xa2,
-    QPP = 0x32,
-} FlashCMD;
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    MemoryRegion mmlqspi;
-
-    qemu_irq irq;
-    int irqline;
-
-    uint8_t num_cs;
-    uint8_t num_busses;
-
-    uint8_t snoop_state;
-    qemu_irq *cs_lines;
-    SSIBus **spi;
-
-    Fifo8 rx_fifo;
-    Fifo8 tx_fifo;
-
-    uint8_t num_txrx_bytes;
-
-    uint32_t regs[R_MAX];
-
-    uint32_t lqspi_buf[LQSPI_CACHE_SIZE];
-    hwaddr lqspi_cached_addr;
-} XilinxSPIPS;
-
-#define TYPE_XILINX_SPIPS "xilinx,spips"
-
-#define XILINX_SPIPS(obj) \
-     OBJECT_CHECK(XilinxSPIPS, (obj), TYPE_XILINX_SPIPS)
-
-static inline int num_effective_busses(XilinxSPIPS *s)
-{
-    return (s->regs[R_LQSPI_CFG] & LQSPI_CFG_SEP_BUS &&
-            s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1;
-}
-
-static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
-{
-    int i, j;
-    bool found = false;
-    int field = s->regs[R_CONFIG] >> CS_SHIFT;
-
-    for (i = 0; i < s->num_cs; i++) {
-        for (j = 0; j < num_effective_busses(s); j++) {
-            int upage = !!(s->regs[R_LQSPI_STS] & LQSPI_CFG_U_PAGE);
-            int cs_to_set = (j * s->num_cs + i + upage) %
-                                (s->num_cs * s->num_busses);
-
-            if (~field & (1 << i) && !found) {
-                DB_PRINT("selecting slave %d\n", i);
-                qemu_set_irq(s->cs_lines[cs_to_set], 0);
-            } else {
-                qemu_set_irq(s->cs_lines[cs_to_set], 1);
-            }
-        }
-        if (~field & (1 << i)) {
-            found = true;
-        }
-    }
-    if (!found) {
-        s->snoop_state = SNOOP_CHECKING;
-    }
-}
-
-static void xilinx_spips_update_ixr(XilinxSPIPS *s)
-{
-    /* These are set/cleared as they occur */
-    s->regs[R_INTR_STATUS] &= (IXR_TX_FIFO_UNDERFLOW | IXR_RX_FIFO_OVERFLOW |
-                                IXR_TX_FIFO_MODE_FAIL);
-    /* these are pure functions of fifo state, set them here */
-    s->regs[R_INTR_STATUS] |=
-        (fifo8_is_full(&s->rx_fifo) ? IXR_RX_FIFO_FULL : 0) |
-        (s->rx_fifo.num >= s->regs[R_RX_THRES] ? IXR_RX_FIFO_NOT_EMPTY : 0) |
-        (fifo8_is_full(&s->tx_fifo) ? IXR_TX_FIFO_FULL : 0) |
-        (s->tx_fifo.num < s->regs[R_TX_THRES] ? IXR_TX_FIFO_NOT_FULL : 0);
-    /* drive external interrupt pin */
-    int new_irqline = !!(s->regs[R_INTR_MASK] & s->regs[R_INTR_STATUS] &
-                                                                IXR_ALL);
-    if (new_irqline != s->irqline) {
-        s->irqline = new_irqline;
-        qemu_set_irq(s->irq, s->irqline);
-    }
-}
-
-static void xilinx_spips_reset(DeviceState *d)
-{
-    XilinxSPIPS *s = XILINX_SPIPS(d);
-
-    int i;
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-
-    fifo8_reset(&s->rx_fifo);
-    fifo8_reset(&s->rx_fifo);
-    /* non zero resets */
-    s->regs[R_CONFIG] |= MODEFAIL_GEN_EN;
-    s->regs[R_SLAVE_IDLE_COUNT] = 0xFF;
-    s->regs[R_TX_THRES] = 1;
-    s->regs[R_RX_THRES] = 1;
-    /* FIXME: move magic number definition somewhere sensible */
-    s->regs[R_MOD_ID] = 0x01090106;
-    s->regs[R_LQSPI_CFG] = R_LQSPI_CFG_RESET;
-    s->snoop_state = SNOOP_CHECKING;
-    xilinx_spips_update_ixr(s);
-    xilinx_spips_update_cs_lines(s);
-}
-
-static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
-{
-    for (;;) {
-        int i;
-        uint8_t rx;
-        uint8_t tx = 0;
-
-        for (i = 0; i < num_effective_busses(s); ++i) {
-            if (!i || s->snoop_state == SNOOP_STRIPING) {
-                if (fifo8_is_empty(&s->tx_fifo)) {
-                    s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW;
-                    xilinx_spips_update_ixr(s);
-                    return;
-                } else {
-                    tx = fifo8_pop(&s->tx_fifo);
-                }
-            }
-            rx = ssi_transfer(s->spi[i], (uint32_t)tx);
-            DB_PRINT("tx = %02x rx = %02x\n", tx, rx);
-            if (!i || s->snoop_state == SNOOP_STRIPING) {
-                if (fifo8_is_full(&s->rx_fifo)) {
-                    s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW;
-                    DB_PRINT("rx FIFO overflow");
-                } else {
-                    fifo8_push(&s->rx_fifo, (uint8_t)rx);
-                }
-            }
-        }
-
-        switch (s->snoop_state) {
-        case (SNOOP_CHECKING):
-            switch (tx) { /* new instruction code */
-            case READ: /* 3 address bytes, no dummy bytes/cycles */
-            case PP:
-            case DPP:
-            case QPP:
-                s->snoop_state = 3;
-                break;
-            case FAST_READ: /* 3 address bytes, 1 dummy byte */
-            case DOR:
-            case QOR:
-            case DIOR: /* FIXME: these vary between vendor - set to spansion */
-                s->snoop_state = 4;
-                break;
-            case QIOR: /* 3 address bytes, 2 dummy bytes */
-                s->snoop_state = 6;
-                break;
-            default:
-                s->snoop_state = SNOOP_NONE;
-            }
-            break;
-        case (SNOOP_STRIPING):
-        case (SNOOP_NONE):
-            break;
-        default:
-            s->snoop_state--;
-        }
-    }
-}
-
-static inline void rx_data_bytes(XilinxSPIPS *s, uint32_t *value, int max)
-{
-    int i;
-
-    *value = 0;
-    for (i = 0; i < max && !fifo8_is_empty(&s->rx_fifo); ++i) {
-        uint32_t next = fifo8_pop(&s->rx_fifo) & 0xFF;
-        *value |= next << 8 * (s->regs[R_CONFIG] & ENDIAN ? 3-i : i);
-    }
-}
-
-static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
-                                                        unsigned size)
-{
-    XilinxSPIPS *s = opaque;
-    uint32_t mask = ~0;
-    uint32_t ret;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CONFIG:
-        mask = 0x0002FFFF;
-        break;
-    case R_INTR_STATUS:
-    case R_INTR_MASK:
-        mask = IXR_ALL;
-        break;
-    case  R_EN:
-        mask = 0x1;
-        break;
-    case R_SLAVE_IDLE_COUNT:
-        mask = 0xFF;
-        break;
-    case R_MOD_ID:
-        mask = 0x01FFFFFF;
-        break;
-    case R_INTR_EN:
-    case R_INTR_DIS:
-    case R_TX_DATA:
-        mask = 0;
-        break;
-    case R_RX_DATA:
-        rx_data_bytes(s, &ret, s->num_txrx_bytes);
-        DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
-        xilinx_spips_update_ixr(s);
-        return ret;
-    }
-    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, s->regs[addr] & mask);
-    return s->regs[addr] & mask;
-
-}
-
-static inline void tx_data_bytes(XilinxSPIPS *s, uint32_t value, int num)
-{
-    int i;
-    for (i = 0; i < num && !fifo8_is_full(&s->tx_fifo); ++i) {
-        if (s->regs[R_CONFIG] & ENDIAN) {
-            fifo8_push(&s->tx_fifo, (uint8_t)(value >> 24));
-            value <<= 8;
-        } else {
-            fifo8_push(&s->tx_fifo, (uint8_t)value);
-            value >>= 8;
-        }
-    }
-}
-
-static void xilinx_spips_write(void *opaque, hwaddr addr,
-                                        uint64_t value, unsigned size)
-{
-    int mask = ~0;
-    int man_start_com = 0;
-    XilinxSPIPS *s = opaque;
-
-    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value);
-    addr >>= 2;
-    switch (addr) {
-    case R_CONFIG:
-        mask = 0x0002FFFF;
-        if (value & MAN_START_COM) {
-            man_start_com = 1;
-        }
-        break;
-    case R_INTR_STATUS:
-        mask = IXR_ALL;
-        s->regs[R_INTR_STATUS] &= ~(mask & value);
-        goto no_reg_update;
-    case R_INTR_DIS:
-        mask = IXR_ALL;
-        s->regs[R_INTR_MASK] &= ~(mask & value);
-        goto no_reg_update;
-    case R_INTR_EN:
-        mask = IXR_ALL;
-        s->regs[R_INTR_MASK] |= mask & value;
-        goto no_reg_update;
-    case R_EN:
-        mask = 0x1;
-        break;
-    case R_SLAVE_IDLE_COUNT:
-        mask = 0xFF;
-        break;
-    case R_RX_DATA:
-    case R_INTR_MASK:
-    case R_MOD_ID:
-        mask = 0;
-        break;
-    case R_TX_DATA:
-        tx_data_bytes(s, (uint32_t)value, s->num_txrx_bytes);
-        goto no_reg_update;
-    case R_TXD1:
-        tx_data_bytes(s, (uint32_t)value, 1);
-        goto no_reg_update;
-    case R_TXD2:
-        tx_data_bytes(s, (uint32_t)value, 2);
-        goto no_reg_update;
-    case R_TXD3:
-        tx_data_bytes(s, (uint32_t)value, 3);
-        goto no_reg_update;
-    }
-    s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask);
-no_reg_update:
-    if (man_start_com) {
-        xilinx_spips_flush_txfifo(s);
-    }
-    xilinx_spips_update_ixr(s);
-    xilinx_spips_update_cs_lines(s);
-}
-
-static const MemoryRegionOps spips_ops = {
-    .read = xilinx_spips_read,
-    .write = xilinx_spips_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-#define LQSPI_CACHE_SIZE 1024
-
-static uint64_t
-lqspi_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    int i;
-    XilinxSPIPS *s = opaque;
-
-    if (addr >= s->lqspi_cached_addr &&
-            addr <= s->lqspi_cached_addr + LQSPI_CACHE_SIZE - 4) {
-        return s->lqspi_buf[(addr - s->lqspi_cached_addr) >> 2];
-    } else {
-        int flash_addr = (addr / num_effective_busses(s));
-        int slave = flash_addr >> LQSPI_ADDRESS_BITS;
-        int cache_entry = 0;
-
-        DB_PRINT("config reg status: %08x\n", s->regs[R_LQSPI_CFG]);
-
-        fifo8_reset(&s->tx_fifo);
-        fifo8_reset(&s->rx_fifo);
-
-        s->regs[R_CONFIG] &= ~CS;
-        s->regs[R_CONFIG] |= (~(1 << slave) << CS_SHIFT) & CS;
-        xilinx_spips_update_cs_lines(s);
-
-        /* instruction */
-        DB_PRINT("pushing read instruction: %02x\n",
-                 (uint8_t)(s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE));
-        fifo8_push(&s->tx_fifo, s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE);
-        /* read address */
-        DB_PRINT("pushing read address %06x\n", flash_addr);
-        fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 16));
-        fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 8));
-        fifo8_push(&s->tx_fifo, (uint8_t)flash_addr);
-        /* mode bits */
-        if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_MODE_EN) {
-            fifo8_push(&s->tx_fifo, extract32(s->regs[R_LQSPI_CFG],
-                                              LQSPI_CFG_MODE_SHIFT,
-                                              LQSPI_CFG_MODE_WIDTH));
-        }
-        /* dummy bytes */
-        for (i = 0; i < (extract32(s->regs[R_LQSPI_CFG], LQSPI_CFG_DUMMY_SHIFT,
-                                   LQSPI_CFG_DUMMY_WIDTH)); ++i) {
-            DB_PRINT("pushing dummy byte\n");
-            fifo8_push(&s->tx_fifo, 0);
-        }
-        xilinx_spips_flush_txfifo(s);
-        fifo8_reset(&s->rx_fifo);
-
-        DB_PRINT("starting QSPI data read\n");
-
-        for (i = 0; i < LQSPI_CACHE_SIZE / 4; ++i) {
-            tx_data_bytes(s, 0, 4);
-            xilinx_spips_flush_txfifo(s);
-            rx_data_bytes(s, &s->lqspi_buf[cache_entry], 4);
-            cache_entry++;
-        }
-
-        s->regs[R_CONFIG] |= CS;
-        xilinx_spips_update_cs_lines(s);
-
-        s->lqspi_cached_addr = addr;
-        return lqspi_read(opaque, addr, size);
-    }
-}
-
-static const MemoryRegionOps lqspi_ops = {
-    .read = lqspi_read,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static void xilinx_spips_realize(DeviceState *dev, Error **errp)
-{
-    XilinxSPIPS *s = XILINX_SPIPS(dev);
-    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-    int i;
-
-    DB_PRINT("inited device model\n");
-
-    s->spi = g_new(SSIBus *, s->num_busses);
-    for (i = 0; i < s->num_busses; ++i) {
-        char bus_name[16];
-        snprintf(bus_name, 16, "spi%d", i);
-        s->spi[i] = ssi_create_bus(dev, bus_name);
-    }
-
-    s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses);
-    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[0]);
-    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[1]);
-    sysbus_init_irq(sbd, &s->irq);
-    for (i = 0; i < s->num_cs * s->num_busses; ++i) {
-        sysbus_init_irq(sbd, &s->cs_lines[i]);
-    }
-
-    memory_region_init_io(&s->iomem, &spips_ops, s, "spi", R_MAX*4);
-    sysbus_init_mmio(sbd, &s->iomem);
-
-    memory_region_init_io(&s->mmlqspi, &lqspi_ops, s, "lqspi",
-                          (1 << LQSPI_ADDRESS_BITS) * 2);
-    sysbus_init_mmio(sbd, &s->mmlqspi);
-
-    s->irqline = -1;
-    s->lqspi_cached_addr = ~0ULL;
-
-    fifo8_create(&s->rx_fifo, RXFF_A);
-    fifo8_create(&s->tx_fifo, TXFF_A);
-}
-
-static int xilinx_spips_post_load(void *opaque, int version_id)
-{
-    xilinx_spips_update_ixr((XilinxSPIPS *)opaque);
-    xilinx_spips_update_cs_lines((XilinxSPIPS *)opaque);
-    return 0;
-}
-
-static const VMStateDescription vmstate_xilinx_spips = {
-    .name = "xilinx_spips",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .post_load = xilinx_spips_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_FIFO8(tx_fifo, XilinxSPIPS),
-        VMSTATE_FIFO8(rx_fifo, XilinxSPIPS),
-        VMSTATE_UINT32_ARRAY(regs, XilinxSPIPS, R_MAX),
-        VMSTATE_UINT8(snoop_state, XilinxSPIPS),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property xilinx_spips_properties[] = {
-    DEFINE_PROP_UINT8("num-busses", XilinxSPIPS, num_busses, 1),
-    DEFINE_PROP_UINT8("num-ss-bits", XilinxSPIPS, num_cs, 4),
-    DEFINE_PROP_UINT8("num-txrx-bytes", XilinxSPIPS, num_txrx_bytes, 1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-static void xilinx_spips_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->realize = xilinx_spips_realize;
-    dc->reset = xilinx_spips_reset;
-    dc->props = xilinx_spips_properties;
-    dc->vmsd = &vmstate_xilinx_spips;
-}
-
-static const TypeInfo xilinx_spips_info = {
-    .name  = TYPE_XILINX_SPIPS,
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size  = sizeof(XilinxSPIPS),
-    .class_init = xilinx_spips_class_init,
-};
-
-static void xilinx_spips_register_types(void)
-{
-    type_register_static(&xilinx_spips_info);
-}
-
-type_init(xilinx_spips_register_types)