xref: /openbmc/qemu/hw/ssi/xilinx_spi.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
131e17060SPaolo Bonzini /*
231e17060SPaolo Bonzini  * QEMU model of the Xilinx SPI Controller
331e17060SPaolo Bonzini  *
431e17060SPaolo Bonzini  * Copyright (C) 2010 Edgar E. Iglesias.
531e17060SPaolo Bonzini  * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
631e17060SPaolo Bonzini  * Copyright (C) 2012 PetaLogix
731e17060SPaolo Bonzini  *
831e17060SPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
931e17060SPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
1031e17060SPaolo Bonzini  * in the Software without restriction, including without limitation the rights
1131e17060SPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1231e17060SPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1331e17060SPaolo Bonzini  * furnished to do so, subject to the following conditions:
1431e17060SPaolo Bonzini  *
1531e17060SPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1631e17060SPaolo Bonzini  * all copies or substantial portions of the Software.
1731e17060SPaolo Bonzini  *
1831e17060SPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1931e17060SPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2031e17060SPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2131e17060SPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2231e17060SPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2331e17060SPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2431e17060SPaolo Bonzini  * THE SOFTWARE.
2531e17060SPaolo Bonzini  */
2631e17060SPaolo Bonzini 
278ef94f0bSPeter Maydell #include "qemu/osdep.h"
2831e17060SPaolo Bonzini #include "hw/sysbus.h"
29d6454270SMarkus Armbruster #include "migration/vmstate.h"
300b8fa32fSMarkus Armbruster #include "qemu/module.h"
3131e17060SPaolo Bonzini #include "qemu/fifo8.h"
3231e17060SPaolo Bonzini 
3364552b6bSMarkus Armbruster #include "hw/irq.h"
34a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
358fd06719SAlistair Francis #include "hw/ssi/ssi.h"
36db1015e9SEduardo Habkost #include "qom/object.h"
3731e17060SPaolo Bonzini 
3831e17060SPaolo Bonzini #ifdef XILINX_SPI_ERR_DEBUG
3931e17060SPaolo Bonzini #define DB_PRINT(...) do { \
4031e17060SPaolo Bonzini     fprintf(stderr,  ": %s: ", __func__); \
4131e17060SPaolo Bonzini     fprintf(stderr, ## __VA_ARGS__); \
422562755eSEric Blake     } while (0)
4331e17060SPaolo Bonzini #else
4431e17060SPaolo Bonzini     #define DB_PRINT(...)
4531e17060SPaolo Bonzini #endif
4631e17060SPaolo Bonzini 
4731e17060SPaolo Bonzini #define R_DGIER     (0x1c / 4)
4831e17060SPaolo Bonzini #define R_DGIER_IE  (1 << 31)
4931e17060SPaolo Bonzini 
5031e17060SPaolo Bonzini #define R_IPISR     (0x20 / 4)
5131e17060SPaolo Bonzini #define IRQ_DRR_NOT_EMPTY    (1 << (31 - 23))
5231e17060SPaolo Bonzini #define IRQ_DRR_OVERRUN      (1 << (31 - 26))
5331e17060SPaolo Bonzini #define IRQ_DRR_FULL         (1 << (31 - 27))
5431e17060SPaolo Bonzini #define IRQ_TX_FF_HALF_EMPTY (1 << 6)
5531e17060SPaolo Bonzini #define IRQ_DTR_UNDERRUN     (1 << 3)
5631e17060SPaolo Bonzini #define IRQ_DTR_EMPTY        (1 << (31 - 29))
5731e17060SPaolo Bonzini 
5831e17060SPaolo Bonzini #define R_IPIER     (0x28 / 4)
5931e17060SPaolo Bonzini #define R_SRR       (0x40 / 4)
6031e17060SPaolo Bonzini #define R_SPICR     (0x60 / 4)
6131e17060SPaolo Bonzini #define R_SPICR_TXFF_RST     (1 << 5)
6231e17060SPaolo Bonzini #define R_SPICR_RXFF_RST     (1 << 6)
6331e17060SPaolo Bonzini #define R_SPICR_MTI          (1 << 8)
6431e17060SPaolo Bonzini 
6531e17060SPaolo Bonzini #define R_SPISR     (0x64 / 4)
6631e17060SPaolo Bonzini #define SR_TX_FULL    (1 << 3)
6731e17060SPaolo Bonzini #define SR_TX_EMPTY   (1 << 2)
6831e17060SPaolo Bonzini #define SR_RX_FULL    (1 << 1)
6931e17060SPaolo Bonzini #define SR_RX_EMPTY   (1 << 0)
7031e17060SPaolo Bonzini 
7131e17060SPaolo Bonzini #define R_SPIDTR    (0x68 / 4)
7231e17060SPaolo Bonzini #define R_SPIDRR    (0x6C / 4)
7331e17060SPaolo Bonzini #define R_SPISSR    (0x70 / 4)
7431e17060SPaolo Bonzini #define R_TX_FF_OCY (0x74 / 4)
7531e17060SPaolo Bonzini #define R_RX_FF_OCY (0x78 / 4)
7631e17060SPaolo Bonzini #define R_MAX       (0x7C / 4)
7731e17060SPaolo Bonzini 
7831e17060SPaolo Bonzini #define FIFO_CAPACITY 256
7931e17060SPaolo Bonzini 
803efc10e1SAndreas Färber #define TYPE_XILINX_SPI "xlnx.xps-spi"
818063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(XilinxSPI, XILINX_SPI)
823efc10e1SAndreas Färber 
83db1015e9SEduardo Habkost struct XilinxSPI {
843efc10e1SAndreas Färber     SysBusDevice parent_obj;
853efc10e1SAndreas Färber 
8631e17060SPaolo Bonzini     MemoryRegion mmio;
8731e17060SPaolo Bonzini 
8831e17060SPaolo Bonzini     qemu_irq irq;
8931e17060SPaolo Bonzini     int irqline;
9031e17060SPaolo Bonzini 
9131e17060SPaolo Bonzini     uint8_t num_cs;
9231e17060SPaolo Bonzini     qemu_irq *cs_lines;
9331e17060SPaolo Bonzini 
9431e17060SPaolo Bonzini     SSIBus *spi;
9531e17060SPaolo Bonzini 
9631e17060SPaolo Bonzini     Fifo8 rx_fifo;
9731e17060SPaolo Bonzini     Fifo8 tx_fifo;
9831e17060SPaolo Bonzini 
9931e17060SPaolo Bonzini     uint32_t regs[R_MAX];
100db1015e9SEduardo Habkost };
10131e17060SPaolo Bonzini 
txfifo_reset(XilinxSPI * s)10231e17060SPaolo Bonzini static void txfifo_reset(XilinxSPI *s)
10331e17060SPaolo Bonzini {
10431e17060SPaolo Bonzini     fifo8_reset(&s->tx_fifo);
10531e17060SPaolo Bonzini 
10631e17060SPaolo Bonzini     s->regs[R_SPISR] &= ~SR_TX_FULL;
10731e17060SPaolo Bonzini     s->regs[R_SPISR] |= SR_TX_EMPTY;
10831e17060SPaolo Bonzini }
10931e17060SPaolo Bonzini 
rxfifo_reset(XilinxSPI * s)11031e17060SPaolo Bonzini static void rxfifo_reset(XilinxSPI *s)
11131e17060SPaolo Bonzini {
11231e17060SPaolo Bonzini     fifo8_reset(&s->rx_fifo);
11331e17060SPaolo Bonzini 
11431e17060SPaolo Bonzini     s->regs[R_SPISR] |= SR_RX_EMPTY;
11531e17060SPaolo Bonzini     s->regs[R_SPISR] &= ~SR_RX_FULL;
11631e17060SPaolo Bonzini }
11731e17060SPaolo Bonzini 
xlx_spi_update_cs(XilinxSPI * s)11831e17060SPaolo Bonzini static void xlx_spi_update_cs(XilinxSPI *s)
11931e17060SPaolo Bonzini {
12031e17060SPaolo Bonzini     int i;
12131e17060SPaolo Bonzini 
12231e17060SPaolo Bonzini     for (i = 0; i < s->num_cs; ++i) {
12331e17060SPaolo Bonzini         qemu_set_irq(s->cs_lines[i], !(~s->regs[R_SPISSR] & 1 << i));
12431e17060SPaolo Bonzini     }
12531e17060SPaolo Bonzini }
12631e17060SPaolo Bonzini 
xlx_spi_update_irq(XilinxSPI * s)12731e17060SPaolo Bonzini static void xlx_spi_update_irq(XilinxSPI *s)
12831e17060SPaolo Bonzini {
12931e17060SPaolo Bonzini     uint32_t pending;
13031e17060SPaolo Bonzini 
13131e17060SPaolo Bonzini     s->regs[R_IPISR] |=
13231e17060SPaolo Bonzini             (!fifo8_is_empty(&s->rx_fifo) ? IRQ_DRR_NOT_EMPTY : 0) |
13331e17060SPaolo Bonzini             (fifo8_is_full(&s->rx_fifo) ? IRQ_DRR_FULL : 0);
13431e17060SPaolo Bonzini 
13531e17060SPaolo Bonzini     pending = s->regs[R_IPISR] & s->regs[R_IPIER];
13631e17060SPaolo Bonzini 
13731e17060SPaolo Bonzini     pending = pending && (s->regs[R_DGIER] & R_DGIER_IE);
13831e17060SPaolo Bonzini     pending = !!pending;
13931e17060SPaolo Bonzini 
14031e17060SPaolo Bonzini     /* This call lies right in the data paths so don't call the
14131e17060SPaolo Bonzini        irq chain unless things really changed.  */
14231e17060SPaolo Bonzini     if (pending != s->irqline) {
14331e17060SPaolo Bonzini         s->irqline = pending;
1449df0a972SAlexChen         DB_PRINT("irq_change of state %u ISR:%x IER:%X\n",
14531e17060SPaolo Bonzini                     pending, s->regs[R_IPISR], s->regs[R_IPIER]);
14631e17060SPaolo Bonzini         qemu_set_irq(s->irq, pending);
14731e17060SPaolo Bonzini     }
14831e17060SPaolo Bonzini 
14931e17060SPaolo Bonzini }
15031e17060SPaolo Bonzini 
xlx_spi_do_reset(XilinxSPI * s)15131e17060SPaolo Bonzini static void xlx_spi_do_reset(XilinxSPI *s)
15231e17060SPaolo Bonzini {
15331e17060SPaolo Bonzini     memset(s->regs, 0, sizeof s->regs);
15431e17060SPaolo Bonzini 
15531e17060SPaolo Bonzini     rxfifo_reset(s);
15631e17060SPaolo Bonzini     txfifo_reset(s);
15731e17060SPaolo Bonzini 
15831e17060SPaolo Bonzini     s->regs[R_SPISSR] = ~0;
159a0eaa126SChris Rauer     s->regs[R_SPICR] = R_SPICR_MTI;
16031e17060SPaolo Bonzini     xlx_spi_update_irq(s);
16131e17060SPaolo Bonzini     xlx_spi_update_cs(s);
16231e17060SPaolo Bonzini }
16331e17060SPaolo Bonzini 
xlx_spi_reset(DeviceState * d)16431e17060SPaolo Bonzini static void xlx_spi_reset(DeviceState *d)
16531e17060SPaolo Bonzini {
1663efc10e1SAndreas Färber     xlx_spi_do_reset(XILINX_SPI(d));
16731e17060SPaolo Bonzini }
16831e17060SPaolo Bonzini 
spi_master_enabled(XilinxSPI * s)16931e17060SPaolo Bonzini static inline int spi_master_enabled(XilinxSPI *s)
17031e17060SPaolo Bonzini {
17131e17060SPaolo Bonzini     return !(s->regs[R_SPICR] & R_SPICR_MTI);
17231e17060SPaolo Bonzini }
17331e17060SPaolo Bonzini 
spi_flush_txfifo(XilinxSPI * s)17431e17060SPaolo Bonzini static void spi_flush_txfifo(XilinxSPI *s)
17531e17060SPaolo Bonzini {
17631e17060SPaolo Bonzini     uint32_t tx;
17731e17060SPaolo Bonzini     uint32_t rx;
17831e17060SPaolo Bonzini 
17931e17060SPaolo Bonzini     while (!fifo8_is_empty(&s->tx_fifo)) {
18031e17060SPaolo Bonzini         tx = (uint32_t)fifo8_pop(&s->tx_fifo);
18131e17060SPaolo Bonzini         DB_PRINT("data tx:%x\n", tx);
18231e17060SPaolo Bonzini         rx = ssi_transfer(s->spi, tx);
18331e17060SPaolo Bonzini         DB_PRINT("data rx:%x\n", rx);
18431e17060SPaolo Bonzini         if (fifo8_is_full(&s->rx_fifo)) {
18531e17060SPaolo Bonzini             s->regs[R_IPISR] |= IRQ_DRR_OVERRUN;
18631e17060SPaolo Bonzini         } else {
18731e17060SPaolo Bonzini             fifo8_push(&s->rx_fifo, (uint8_t)rx);
18831e17060SPaolo Bonzini             if (fifo8_is_full(&s->rx_fifo)) {
18931e17060SPaolo Bonzini                 s->regs[R_SPISR] |= SR_RX_FULL;
19031e17060SPaolo Bonzini                 s->regs[R_IPISR] |= IRQ_DRR_FULL;
19131e17060SPaolo Bonzini             }
19231e17060SPaolo Bonzini         }
19331e17060SPaolo Bonzini 
19431e17060SPaolo Bonzini         s->regs[R_SPISR] &= ~SR_RX_EMPTY;
19531e17060SPaolo Bonzini         s->regs[R_SPISR] &= ~SR_TX_FULL;
19631e17060SPaolo Bonzini         s->regs[R_SPISR] |= SR_TX_EMPTY;
19731e17060SPaolo Bonzini 
19831e17060SPaolo Bonzini         s->regs[R_IPISR] |= IRQ_DTR_EMPTY;
19931e17060SPaolo Bonzini         s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY;
20031e17060SPaolo Bonzini     }
20131e17060SPaolo Bonzini 
20231e17060SPaolo Bonzini }
20331e17060SPaolo Bonzini 
20431e17060SPaolo Bonzini static uint64_t
spi_read(void * opaque,hwaddr addr,unsigned int size)20531e17060SPaolo Bonzini spi_read(void *opaque, hwaddr addr, unsigned int size)
20631e17060SPaolo Bonzini {
20731e17060SPaolo Bonzini     XilinxSPI *s = opaque;
20831e17060SPaolo Bonzini     uint32_t r = 0;
20931e17060SPaolo Bonzini 
21031e17060SPaolo Bonzini     addr >>= 2;
21131e17060SPaolo Bonzini     switch (addr) {
21231e17060SPaolo Bonzini     case R_SPIDRR:
21331e17060SPaolo Bonzini         if (fifo8_is_empty(&s->rx_fifo)) {
21431e17060SPaolo Bonzini             DB_PRINT("Read from empty FIFO!\n");
21531e17060SPaolo Bonzini             return 0xdeadbeef;
21631e17060SPaolo Bonzini         }
21731e17060SPaolo Bonzini 
21831e17060SPaolo Bonzini         s->regs[R_SPISR] &= ~SR_RX_FULL;
21931e17060SPaolo Bonzini         r = fifo8_pop(&s->rx_fifo);
22031e17060SPaolo Bonzini         if (fifo8_is_empty(&s->rx_fifo)) {
22131e17060SPaolo Bonzini             s->regs[R_SPISR] |= SR_RX_EMPTY;
22231e17060SPaolo Bonzini         }
22331e17060SPaolo Bonzini         break;
22431e17060SPaolo Bonzini 
22531e17060SPaolo Bonzini     case R_SPISR:
22631e17060SPaolo Bonzini         r = s->regs[addr];
22731e17060SPaolo Bonzini         break;
22831e17060SPaolo Bonzini 
22931e17060SPaolo Bonzini     default:
23031e17060SPaolo Bonzini         if (addr < ARRAY_SIZE(s->regs)) {
23131e17060SPaolo Bonzini             r = s->regs[addr];
23231e17060SPaolo Bonzini         }
23331e17060SPaolo Bonzini         break;
23431e17060SPaolo Bonzini 
23531e17060SPaolo Bonzini     }
236883f2c59SPhilippe Mathieu-Daudé     DB_PRINT("addr=" HWADDR_FMT_plx " = %x\n", addr * 4, r);
23731e17060SPaolo Bonzini     xlx_spi_update_irq(s);
23831e17060SPaolo Bonzini     return r;
23931e17060SPaolo Bonzini }
24031e17060SPaolo Bonzini 
24131e17060SPaolo Bonzini static void
spi_write(void * opaque,hwaddr addr,uint64_t val64,unsigned int size)24231e17060SPaolo Bonzini spi_write(void *opaque, hwaddr addr,
24331e17060SPaolo Bonzini             uint64_t val64, unsigned int size)
24431e17060SPaolo Bonzini {
24531e17060SPaolo Bonzini     XilinxSPI *s = opaque;
24631e17060SPaolo Bonzini     uint32_t value = val64;
24731e17060SPaolo Bonzini 
248883f2c59SPhilippe Mathieu-Daudé     DB_PRINT("addr=" HWADDR_FMT_plx " = %x\n", addr, value);
24931e17060SPaolo Bonzini     addr >>= 2;
25031e17060SPaolo Bonzini     switch (addr) {
25131e17060SPaolo Bonzini     case R_SRR:
25231e17060SPaolo Bonzini         if (value != 0xa) {
25331e17060SPaolo Bonzini             DB_PRINT("Invalid write to SRR %x\n", value);
25431e17060SPaolo Bonzini         } else {
25531e17060SPaolo Bonzini             xlx_spi_do_reset(s);
25631e17060SPaolo Bonzini         }
25731e17060SPaolo Bonzini         break;
25831e17060SPaolo Bonzini 
25931e17060SPaolo Bonzini     case R_SPIDTR:
26031e17060SPaolo Bonzini         s->regs[R_SPISR] &= ~SR_TX_EMPTY;
26131e17060SPaolo Bonzini         fifo8_push(&s->tx_fifo, (uint8_t)value);
26231e17060SPaolo Bonzini         if (fifo8_is_full(&s->tx_fifo)) {
26331e17060SPaolo Bonzini             s->regs[R_SPISR] |= SR_TX_FULL;
26431e17060SPaolo Bonzini         }
26531e17060SPaolo Bonzini         if (!spi_master_enabled(s)) {
26631e17060SPaolo Bonzini             goto done;
26731e17060SPaolo Bonzini         } else {
26831e17060SPaolo Bonzini             DB_PRINT("DTR and master enabled\n");
26931e17060SPaolo Bonzini         }
27031e17060SPaolo Bonzini         spi_flush_txfifo(s);
27131e17060SPaolo Bonzini         break;
27231e17060SPaolo Bonzini 
27331e17060SPaolo Bonzini     case R_SPISR:
27431e17060SPaolo Bonzini         DB_PRINT("Invalid write to SPISR %x\n", value);
27531e17060SPaolo Bonzini         break;
27631e17060SPaolo Bonzini 
27731e17060SPaolo Bonzini     case R_IPISR:
27831e17060SPaolo Bonzini         /* Toggle the bits.  */
27931e17060SPaolo Bonzini         s->regs[addr] ^= value;
28031e17060SPaolo Bonzini         break;
28131e17060SPaolo Bonzini 
28231e17060SPaolo Bonzini     /* Slave Select Register.  */
28331e17060SPaolo Bonzini     case R_SPISSR:
28431e17060SPaolo Bonzini         s->regs[addr] = value;
28531e17060SPaolo Bonzini         xlx_spi_update_cs(s);
28631e17060SPaolo Bonzini         break;
28731e17060SPaolo Bonzini 
28831e17060SPaolo Bonzini     case R_SPICR:
28931e17060SPaolo Bonzini         /* FIXME: reset irq and sr state to empty queues.  */
29031e17060SPaolo Bonzini         if (value & R_SPICR_RXFF_RST) {
29131e17060SPaolo Bonzini             rxfifo_reset(s);
29231e17060SPaolo Bonzini         }
29331e17060SPaolo Bonzini 
29431e17060SPaolo Bonzini         if (value & R_SPICR_TXFF_RST) {
29531e17060SPaolo Bonzini             txfifo_reset(s);
29631e17060SPaolo Bonzini         }
29731e17060SPaolo Bonzini         value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST);
29831e17060SPaolo Bonzini         s->regs[addr] = value;
29931e17060SPaolo Bonzini 
30031e17060SPaolo Bonzini         if (!(value & R_SPICR_MTI)) {
30131e17060SPaolo Bonzini             spi_flush_txfifo(s);
30231e17060SPaolo Bonzini         }
30331e17060SPaolo Bonzini         break;
30431e17060SPaolo Bonzini 
30531e17060SPaolo Bonzini     default:
30631e17060SPaolo Bonzini         if (addr < ARRAY_SIZE(s->regs)) {
30731e17060SPaolo Bonzini             s->regs[addr] = value;
30831e17060SPaolo Bonzini         }
30931e17060SPaolo Bonzini         break;
31031e17060SPaolo Bonzini     }
31131e17060SPaolo Bonzini 
31231e17060SPaolo Bonzini done:
31331e17060SPaolo Bonzini     xlx_spi_update_irq(s);
31431e17060SPaolo Bonzini }
31531e17060SPaolo Bonzini 
31631e17060SPaolo Bonzini static const MemoryRegionOps spi_ops = {
31731e17060SPaolo Bonzini     .read = spi_read,
31831e17060SPaolo Bonzini     .write = spi_write,
31931e17060SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
32031e17060SPaolo Bonzini     .valid = {
32131e17060SPaolo Bonzini         .min_access_size = 4,
32231e17060SPaolo Bonzini         .max_access_size = 4
32331e17060SPaolo Bonzini     }
32431e17060SPaolo Bonzini };
32531e17060SPaolo Bonzini 
xilinx_spi_realize(DeviceState * dev,Error ** errp)326a7e1562cSPhilippe Mathieu-Daudé static void xilinx_spi_realize(DeviceState *dev, Error **errp)
32731e17060SPaolo Bonzini {
328a7e1562cSPhilippe Mathieu-Daudé     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
3293efc10e1SAndreas Färber     XilinxSPI *s = XILINX_SPI(dev);
33031e17060SPaolo Bonzini     int i;
33131e17060SPaolo Bonzini 
33231e17060SPaolo Bonzini     DB_PRINT("\n");
33331e17060SPaolo Bonzini 
3343efc10e1SAndreas Färber     s->spi = ssi_create_bus(dev, "spi");
33531e17060SPaolo Bonzini 
3363efc10e1SAndreas Färber     sysbus_init_irq(sbd, &s->irq);
337c75f3c04SPeter Crosthwaite     s->cs_lines = g_new0(qemu_irq, s->num_cs);
33831e17060SPaolo Bonzini     for (i = 0; i < s->num_cs; ++i) {
3393efc10e1SAndreas Färber         sysbus_init_irq(sbd, &s->cs_lines[i]);
34031e17060SPaolo Bonzini     }
34131e17060SPaolo Bonzini 
34229776739SPaolo Bonzini     memory_region_init_io(&s->mmio, OBJECT(s), &spi_ops, s,
34329776739SPaolo Bonzini                           "xilinx-spi", R_MAX * 4);
3443efc10e1SAndreas Färber     sysbus_init_mmio(sbd, &s->mmio);
34531e17060SPaolo Bonzini 
34631e17060SPaolo Bonzini     s->irqline = -1;
34731e17060SPaolo Bonzini 
34831e17060SPaolo Bonzini     fifo8_create(&s->tx_fifo, FIFO_CAPACITY);
34931e17060SPaolo Bonzini     fifo8_create(&s->rx_fifo, FIFO_CAPACITY);
35031e17060SPaolo Bonzini }
35131e17060SPaolo Bonzini 
35231e17060SPaolo Bonzini static const VMStateDescription vmstate_xilinx_spi = {
35331e17060SPaolo Bonzini     .name = "xilinx_spi",
35431e17060SPaolo Bonzini     .version_id = 1,
35531e17060SPaolo Bonzini     .minimum_version_id = 1,
3560aa6c7dfSRichard Henderson     .fields = (const VMStateField[]) {
35731e17060SPaolo Bonzini         VMSTATE_FIFO8(tx_fifo, XilinxSPI),
35831e17060SPaolo Bonzini         VMSTATE_FIFO8(rx_fifo, XilinxSPI),
35931e17060SPaolo Bonzini         VMSTATE_UINT32_ARRAY(regs, XilinxSPI, R_MAX),
36031e17060SPaolo Bonzini         VMSTATE_END_OF_LIST()
36131e17060SPaolo Bonzini     }
36231e17060SPaolo Bonzini };
36331e17060SPaolo Bonzini 
36431e17060SPaolo Bonzini static Property xilinx_spi_properties[] = {
36531e17060SPaolo Bonzini     DEFINE_PROP_UINT8("num-ss-bits", XilinxSPI, num_cs, 1),
36631e17060SPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
36731e17060SPaolo Bonzini };
36831e17060SPaolo Bonzini 
xilinx_spi_class_init(ObjectClass * klass,void * data)36931e17060SPaolo Bonzini static void xilinx_spi_class_init(ObjectClass *klass, void *data)
37031e17060SPaolo Bonzini {
37131e17060SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
37231e17060SPaolo Bonzini 
373a7e1562cSPhilippe Mathieu-Daudé     dc->realize = xilinx_spi_realize;
374*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, xlx_spi_reset);
3754f67d30bSMarc-André Lureau     device_class_set_props(dc, xilinx_spi_properties);
37631e17060SPaolo Bonzini     dc->vmsd = &vmstate_xilinx_spi;
37731e17060SPaolo Bonzini }
37831e17060SPaolo Bonzini 
37931e17060SPaolo Bonzini static const TypeInfo xilinx_spi_info = {
3803efc10e1SAndreas Färber     .name           = TYPE_XILINX_SPI,
38131e17060SPaolo Bonzini     .parent         = TYPE_SYS_BUS_DEVICE,
38231e17060SPaolo Bonzini     .instance_size  = sizeof(XilinxSPI),
38331e17060SPaolo Bonzini     .class_init     = xilinx_spi_class_init,
38431e17060SPaolo Bonzini };
38531e17060SPaolo Bonzini 
xilinx_spi_register_types(void)38631e17060SPaolo Bonzini static void xilinx_spi_register_types(void)
38731e17060SPaolo Bonzini {
38831e17060SPaolo Bonzini     type_register_static(&xilinx_spi_info);
38931e17060SPaolo Bonzini }
39031e17060SPaolo Bonzini 
39131e17060SPaolo Bonzini type_init(xilinx_spi_register_types)
392