xref: /openbmc/qemu/hw/ssi/xilinx_spi.c (revision c75f3c041aff0d6192049860a8f7b4db40ec0603)
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 
2731e17060SPaolo Bonzini #include "hw/sysbus.h"
2831e17060SPaolo Bonzini #include "sysemu/sysemu.h"
2931e17060SPaolo Bonzini #include "qemu/log.h"
3031e17060SPaolo Bonzini #include "qemu/fifo8.h"
3131e17060SPaolo Bonzini 
3231e17060SPaolo Bonzini #include "hw/ssi.h"
3331e17060SPaolo Bonzini 
3431e17060SPaolo Bonzini #ifdef XILINX_SPI_ERR_DEBUG
3531e17060SPaolo Bonzini #define DB_PRINT(...) do { \
3631e17060SPaolo Bonzini     fprintf(stderr,  ": %s: ", __func__); \
3731e17060SPaolo Bonzini     fprintf(stderr, ## __VA_ARGS__); \
3831e17060SPaolo Bonzini     } while (0);
3931e17060SPaolo Bonzini #else
4031e17060SPaolo Bonzini     #define DB_PRINT(...)
4131e17060SPaolo Bonzini #endif
4231e17060SPaolo Bonzini 
4331e17060SPaolo Bonzini #define R_DGIER     (0x1c / 4)
4431e17060SPaolo Bonzini #define R_DGIER_IE  (1 << 31)
4531e17060SPaolo Bonzini 
4631e17060SPaolo Bonzini #define R_IPISR     (0x20 / 4)
4731e17060SPaolo Bonzini #define IRQ_DRR_NOT_EMPTY    (1 << (31 - 23))
4831e17060SPaolo Bonzini #define IRQ_DRR_OVERRUN      (1 << (31 - 26))
4931e17060SPaolo Bonzini #define IRQ_DRR_FULL         (1 << (31 - 27))
5031e17060SPaolo Bonzini #define IRQ_TX_FF_HALF_EMPTY (1 << 6)
5131e17060SPaolo Bonzini #define IRQ_DTR_UNDERRUN     (1 << 3)
5231e17060SPaolo Bonzini #define IRQ_DTR_EMPTY        (1 << (31 - 29))
5331e17060SPaolo Bonzini 
5431e17060SPaolo Bonzini #define R_IPIER     (0x28 / 4)
5531e17060SPaolo Bonzini #define R_SRR       (0x40 / 4)
5631e17060SPaolo Bonzini #define R_SPICR     (0x60 / 4)
5731e17060SPaolo Bonzini #define R_SPICR_TXFF_RST     (1 << 5)
5831e17060SPaolo Bonzini #define R_SPICR_RXFF_RST     (1 << 6)
5931e17060SPaolo Bonzini #define R_SPICR_MTI          (1 << 8)
6031e17060SPaolo Bonzini 
6131e17060SPaolo Bonzini #define R_SPISR     (0x64 / 4)
6231e17060SPaolo Bonzini #define SR_TX_FULL    (1 << 3)
6331e17060SPaolo Bonzini #define SR_TX_EMPTY   (1 << 2)
6431e17060SPaolo Bonzini #define SR_RX_FULL    (1 << 1)
6531e17060SPaolo Bonzini #define SR_RX_EMPTY   (1 << 0)
6631e17060SPaolo Bonzini 
6731e17060SPaolo Bonzini #define R_SPIDTR    (0x68 / 4)
6831e17060SPaolo Bonzini #define R_SPIDRR    (0x6C / 4)
6931e17060SPaolo Bonzini #define R_SPISSR    (0x70 / 4)
7031e17060SPaolo Bonzini #define R_TX_FF_OCY (0x74 / 4)
7131e17060SPaolo Bonzini #define R_RX_FF_OCY (0x78 / 4)
7231e17060SPaolo Bonzini #define R_MAX       (0x7C / 4)
7331e17060SPaolo Bonzini 
7431e17060SPaolo Bonzini #define FIFO_CAPACITY 256
7531e17060SPaolo Bonzini 
763efc10e1SAndreas Färber #define TYPE_XILINX_SPI "xlnx.xps-spi"
773efc10e1SAndreas Färber #define XILINX_SPI(obj) OBJECT_CHECK(XilinxSPI, (obj), TYPE_XILINX_SPI)
783efc10e1SAndreas Färber 
7931e17060SPaolo Bonzini typedef struct XilinxSPI {
803efc10e1SAndreas Färber     SysBusDevice parent_obj;
813efc10e1SAndreas Färber 
8231e17060SPaolo Bonzini     MemoryRegion mmio;
8331e17060SPaolo Bonzini 
8431e17060SPaolo Bonzini     qemu_irq irq;
8531e17060SPaolo Bonzini     int irqline;
8631e17060SPaolo Bonzini 
8731e17060SPaolo Bonzini     uint8_t num_cs;
8831e17060SPaolo Bonzini     qemu_irq *cs_lines;
8931e17060SPaolo Bonzini 
9031e17060SPaolo Bonzini     SSIBus *spi;
9131e17060SPaolo Bonzini 
9231e17060SPaolo Bonzini     Fifo8 rx_fifo;
9331e17060SPaolo Bonzini     Fifo8 tx_fifo;
9431e17060SPaolo Bonzini 
9531e17060SPaolo Bonzini     uint32_t regs[R_MAX];
9631e17060SPaolo Bonzini } XilinxSPI;
9731e17060SPaolo Bonzini 
9831e17060SPaolo Bonzini static void txfifo_reset(XilinxSPI *s)
9931e17060SPaolo Bonzini {
10031e17060SPaolo Bonzini     fifo8_reset(&s->tx_fifo);
10131e17060SPaolo Bonzini 
10231e17060SPaolo Bonzini     s->regs[R_SPISR] &= ~SR_TX_FULL;
10331e17060SPaolo Bonzini     s->regs[R_SPISR] |= SR_TX_EMPTY;
10431e17060SPaolo Bonzini }
10531e17060SPaolo Bonzini 
10631e17060SPaolo Bonzini static void rxfifo_reset(XilinxSPI *s)
10731e17060SPaolo Bonzini {
10831e17060SPaolo Bonzini     fifo8_reset(&s->rx_fifo);
10931e17060SPaolo Bonzini 
11031e17060SPaolo Bonzini     s->regs[R_SPISR] |= SR_RX_EMPTY;
11131e17060SPaolo Bonzini     s->regs[R_SPISR] &= ~SR_RX_FULL;
11231e17060SPaolo Bonzini }
11331e17060SPaolo Bonzini 
11431e17060SPaolo Bonzini static void xlx_spi_update_cs(XilinxSPI *s)
11531e17060SPaolo Bonzini {
11631e17060SPaolo Bonzini     int i;
11731e17060SPaolo Bonzini 
11831e17060SPaolo Bonzini     for (i = 0; i < s->num_cs; ++i) {
11931e17060SPaolo Bonzini         qemu_set_irq(s->cs_lines[i], !(~s->regs[R_SPISSR] & 1 << i));
12031e17060SPaolo Bonzini     }
12131e17060SPaolo Bonzini }
12231e17060SPaolo Bonzini 
12331e17060SPaolo Bonzini static void xlx_spi_update_irq(XilinxSPI *s)
12431e17060SPaolo Bonzini {
12531e17060SPaolo Bonzini     uint32_t pending;
12631e17060SPaolo Bonzini 
12731e17060SPaolo Bonzini     s->regs[R_IPISR] |=
12831e17060SPaolo Bonzini             (!fifo8_is_empty(&s->rx_fifo) ? IRQ_DRR_NOT_EMPTY : 0) |
12931e17060SPaolo Bonzini             (fifo8_is_full(&s->rx_fifo) ? IRQ_DRR_FULL : 0);
13031e17060SPaolo Bonzini 
13131e17060SPaolo Bonzini     pending = s->regs[R_IPISR] & s->regs[R_IPIER];
13231e17060SPaolo Bonzini 
13331e17060SPaolo Bonzini     pending = pending && (s->regs[R_DGIER] & R_DGIER_IE);
13431e17060SPaolo Bonzini     pending = !!pending;
13531e17060SPaolo Bonzini 
13631e17060SPaolo Bonzini     /* This call lies right in the data paths so don't call the
13731e17060SPaolo Bonzini        irq chain unless things really changed.  */
13831e17060SPaolo Bonzini     if (pending != s->irqline) {
13931e17060SPaolo Bonzini         s->irqline = pending;
14031e17060SPaolo Bonzini         DB_PRINT("irq_change of state %d ISR:%x IER:%X\n",
14131e17060SPaolo Bonzini                     pending, s->regs[R_IPISR], s->regs[R_IPIER]);
14231e17060SPaolo Bonzini         qemu_set_irq(s->irq, pending);
14331e17060SPaolo Bonzini     }
14431e17060SPaolo Bonzini 
14531e17060SPaolo Bonzini }
14631e17060SPaolo Bonzini 
14731e17060SPaolo Bonzini static void xlx_spi_do_reset(XilinxSPI *s)
14831e17060SPaolo Bonzini {
14931e17060SPaolo Bonzini     memset(s->regs, 0, sizeof s->regs);
15031e17060SPaolo Bonzini 
15131e17060SPaolo Bonzini     rxfifo_reset(s);
15231e17060SPaolo Bonzini     txfifo_reset(s);
15331e17060SPaolo Bonzini 
15431e17060SPaolo Bonzini     s->regs[R_SPISSR] = ~0;
15531e17060SPaolo Bonzini     xlx_spi_update_irq(s);
15631e17060SPaolo Bonzini     xlx_spi_update_cs(s);
15731e17060SPaolo Bonzini }
15831e17060SPaolo Bonzini 
15931e17060SPaolo Bonzini static void xlx_spi_reset(DeviceState *d)
16031e17060SPaolo Bonzini {
1613efc10e1SAndreas Färber     xlx_spi_do_reset(XILINX_SPI(d));
16231e17060SPaolo Bonzini }
16331e17060SPaolo Bonzini 
16431e17060SPaolo Bonzini static inline int spi_master_enabled(XilinxSPI *s)
16531e17060SPaolo Bonzini {
16631e17060SPaolo Bonzini     return !(s->regs[R_SPICR] & R_SPICR_MTI);
16731e17060SPaolo Bonzini }
16831e17060SPaolo Bonzini 
16931e17060SPaolo Bonzini static void spi_flush_txfifo(XilinxSPI *s)
17031e17060SPaolo Bonzini {
17131e17060SPaolo Bonzini     uint32_t tx;
17231e17060SPaolo Bonzini     uint32_t rx;
17331e17060SPaolo Bonzini 
17431e17060SPaolo Bonzini     while (!fifo8_is_empty(&s->tx_fifo)) {
17531e17060SPaolo Bonzini         tx = (uint32_t)fifo8_pop(&s->tx_fifo);
17631e17060SPaolo Bonzini         DB_PRINT("data tx:%x\n", tx);
17731e17060SPaolo Bonzini         rx = ssi_transfer(s->spi, tx);
17831e17060SPaolo Bonzini         DB_PRINT("data rx:%x\n", rx);
17931e17060SPaolo Bonzini         if (fifo8_is_full(&s->rx_fifo)) {
18031e17060SPaolo Bonzini             s->regs[R_IPISR] |= IRQ_DRR_OVERRUN;
18131e17060SPaolo Bonzini         } else {
18231e17060SPaolo Bonzini             fifo8_push(&s->rx_fifo, (uint8_t)rx);
18331e17060SPaolo Bonzini             if (fifo8_is_full(&s->rx_fifo)) {
18431e17060SPaolo Bonzini                 s->regs[R_SPISR] |= SR_RX_FULL;
18531e17060SPaolo Bonzini                 s->regs[R_IPISR] |= IRQ_DRR_FULL;
18631e17060SPaolo Bonzini             }
18731e17060SPaolo Bonzini         }
18831e17060SPaolo Bonzini 
18931e17060SPaolo Bonzini         s->regs[R_SPISR] &= ~SR_RX_EMPTY;
19031e17060SPaolo Bonzini         s->regs[R_SPISR] &= ~SR_TX_FULL;
19131e17060SPaolo Bonzini         s->regs[R_SPISR] |= SR_TX_EMPTY;
19231e17060SPaolo Bonzini 
19331e17060SPaolo Bonzini         s->regs[R_IPISR] |= IRQ_DTR_EMPTY;
19431e17060SPaolo Bonzini         s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY;
19531e17060SPaolo Bonzini     }
19631e17060SPaolo Bonzini 
19731e17060SPaolo Bonzini }
19831e17060SPaolo Bonzini 
19931e17060SPaolo Bonzini static uint64_t
20031e17060SPaolo Bonzini spi_read(void *opaque, hwaddr addr, unsigned int size)
20131e17060SPaolo Bonzini {
20231e17060SPaolo Bonzini     XilinxSPI *s = opaque;
20331e17060SPaolo Bonzini     uint32_t r = 0;
20431e17060SPaolo Bonzini 
20531e17060SPaolo Bonzini     addr >>= 2;
20631e17060SPaolo Bonzini     switch (addr) {
20731e17060SPaolo Bonzini     case R_SPIDRR:
20831e17060SPaolo Bonzini         if (fifo8_is_empty(&s->rx_fifo)) {
20931e17060SPaolo Bonzini             DB_PRINT("Read from empty FIFO!\n");
21031e17060SPaolo Bonzini             return 0xdeadbeef;
21131e17060SPaolo Bonzini         }
21231e17060SPaolo Bonzini 
21331e17060SPaolo Bonzini         s->regs[R_SPISR] &= ~SR_RX_FULL;
21431e17060SPaolo Bonzini         r = fifo8_pop(&s->rx_fifo);
21531e17060SPaolo Bonzini         if (fifo8_is_empty(&s->rx_fifo)) {
21631e17060SPaolo Bonzini             s->regs[R_SPISR] |= SR_RX_EMPTY;
21731e17060SPaolo Bonzini         }
21831e17060SPaolo Bonzini         break;
21931e17060SPaolo Bonzini 
22031e17060SPaolo Bonzini     case R_SPISR:
22131e17060SPaolo Bonzini         r = s->regs[addr];
22231e17060SPaolo Bonzini         break;
22331e17060SPaolo Bonzini 
22431e17060SPaolo Bonzini     default:
22531e17060SPaolo Bonzini         if (addr < ARRAY_SIZE(s->regs)) {
22631e17060SPaolo Bonzini             r = s->regs[addr];
22731e17060SPaolo Bonzini         }
22831e17060SPaolo Bonzini         break;
22931e17060SPaolo Bonzini 
23031e17060SPaolo Bonzini     }
23131e17060SPaolo Bonzini     DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, r);
23231e17060SPaolo Bonzini     xlx_spi_update_irq(s);
23331e17060SPaolo Bonzini     return r;
23431e17060SPaolo Bonzini }
23531e17060SPaolo Bonzini 
23631e17060SPaolo Bonzini static void
23731e17060SPaolo Bonzini spi_write(void *opaque, hwaddr addr,
23831e17060SPaolo Bonzini             uint64_t val64, unsigned int size)
23931e17060SPaolo Bonzini {
24031e17060SPaolo Bonzini     XilinxSPI *s = opaque;
24131e17060SPaolo Bonzini     uint32_t value = val64;
24231e17060SPaolo Bonzini 
24331e17060SPaolo Bonzini     DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, value);
24431e17060SPaolo Bonzini     addr >>= 2;
24531e17060SPaolo Bonzini     switch (addr) {
24631e17060SPaolo Bonzini     case R_SRR:
24731e17060SPaolo Bonzini         if (value != 0xa) {
24831e17060SPaolo Bonzini             DB_PRINT("Invalid write to SRR %x\n", value);
24931e17060SPaolo Bonzini         } else {
25031e17060SPaolo Bonzini             xlx_spi_do_reset(s);
25131e17060SPaolo Bonzini         }
25231e17060SPaolo Bonzini         break;
25331e17060SPaolo Bonzini 
25431e17060SPaolo Bonzini     case R_SPIDTR:
25531e17060SPaolo Bonzini         s->regs[R_SPISR] &= ~SR_TX_EMPTY;
25631e17060SPaolo Bonzini         fifo8_push(&s->tx_fifo, (uint8_t)value);
25731e17060SPaolo Bonzini         if (fifo8_is_full(&s->tx_fifo)) {
25831e17060SPaolo Bonzini             s->regs[R_SPISR] |= SR_TX_FULL;
25931e17060SPaolo Bonzini         }
26031e17060SPaolo Bonzini         if (!spi_master_enabled(s)) {
26131e17060SPaolo Bonzini             goto done;
26231e17060SPaolo Bonzini         } else {
26331e17060SPaolo Bonzini             DB_PRINT("DTR and master enabled\n");
26431e17060SPaolo Bonzini         }
26531e17060SPaolo Bonzini         spi_flush_txfifo(s);
26631e17060SPaolo Bonzini         break;
26731e17060SPaolo Bonzini 
26831e17060SPaolo Bonzini     case R_SPISR:
26931e17060SPaolo Bonzini         DB_PRINT("Invalid write to SPISR %x\n", value);
27031e17060SPaolo Bonzini         break;
27131e17060SPaolo Bonzini 
27231e17060SPaolo Bonzini     case R_IPISR:
27331e17060SPaolo Bonzini         /* Toggle the bits.  */
27431e17060SPaolo Bonzini         s->regs[addr] ^= value;
27531e17060SPaolo Bonzini         break;
27631e17060SPaolo Bonzini 
27731e17060SPaolo Bonzini     /* Slave Select Register.  */
27831e17060SPaolo Bonzini     case R_SPISSR:
27931e17060SPaolo Bonzini         s->regs[addr] = value;
28031e17060SPaolo Bonzini         xlx_spi_update_cs(s);
28131e17060SPaolo Bonzini         break;
28231e17060SPaolo Bonzini 
28331e17060SPaolo Bonzini     case R_SPICR:
28431e17060SPaolo Bonzini         /* FIXME: reset irq and sr state to empty queues.  */
28531e17060SPaolo Bonzini         if (value & R_SPICR_RXFF_RST) {
28631e17060SPaolo Bonzini             rxfifo_reset(s);
28731e17060SPaolo Bonzini         }
28831e17060SPaolo Bonzini 
28931e17060SPaolo Bonzini         if (value & R_SPICR_TXFF_RST) {
29031e17060SPaolo Bonzini             txfifo_reset(s);
29131e17060SPaolo Bonzini         }
29231e17060SPaolo Bonzini         value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST);
29331e17060SPaolo Bonzini         s->regs[addr] = value;
29431e17060SPaolo Bonzini 
29531e17060SPaolo Bonzini         if (!(value & R_SPICR_MTI)) {
29631e17060SPaolo Bonzini             spi_flush_txfifo(s);
29731e17060SPaolo Bonzini         }
29831e17060SPaolo Bonzini         break;
29931e17060SPaolo Bonzini 
30031e17060SPaolo Bonzini     default:
30131e17060SPaolo Bonzini         if (addr < ARRAY_SIZE(s->regs)) {
30231e17060SPaolo Bonzini             s->regs[addr] = value;
30331e17060SPaolo Bonzini         }
30431e17060SPaolo Bonzini         break;
30531e17060SPaolo Bonzini     }
30631e17060SPaolo Bonzini 
30731e17060SPaolo Bonzini done:
30831e17060SPaolo Bonzini     xlx_spi_update_irq(s);
30931e17060SPaolo Bonzini }
31031e17060SPaolo Bonzini 
31131e17060SPaolo Bonzini static const MemoryRegionOps spi_ops = {
31231e17060SPaolo Bonzini     .read = spi_read,
31331e17060SPaolo Bonzini     .write = spi_write,
31431e17060SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
31531e17060SPaolo Bonzini     .valid = {
31631e17060SPaolo Bonzini         .min_access_size = 4,
31731e17060SPaolo Bonzini         .max_access_size = 4
31831e17060SPaolo Bonzini     }
31931e17060SPaolo Bonzini };
32031e17060SPaolo Bonzini 
3213efc10e1SAndreas Färber static int xilinx_spi_init(SysBusDevice *sbd)
32231e17060SPaolo Bonzini {
3233efc10e1SAndreas Färber     DeviceState *dev = DEVICE(sbd);
3243efc10e1SAndreas Färber     XilinxSPI *s = XILINX_SPI(dev);
32531e17060SPaolo Bonzini     int i;
32631e17060SPaolo Bonzini 
32731e17060SPaolo Bonzini     DB_PRINT("\n");
32831e17060SPaolo Bonzini 
3293efc10e1SAndreas Färber     s->spi = ssi_create_bus(dev, "spi");
33031e17060SPaolo Bonzini 
3313efc10e1SAndreas Färber     sysbus_init_irq(sbd, &s->irq);
332*c75f3c04SPeter Crosthwaite     s->cs_lines = g_new0(qemu_irq, s->num_cs);
3333efc10e1SAndreas Färber     ssi_auto_connect_slaves(dev, s->cs_lines, s->spi);
33431e17060SPaolo Bonzini     for (i = 0; i < s->num_cs; ++i) {
3353efc10e1SAndreas Färber         sysbus_init_irq(sbd, &s->cs_lines[i]);
33631e17060SPaolo Bonzini     }
33731e17060SPaolo Bonzini 
33829776739SPaolo Bonzini     memory_region_init_io(&s->mmio, OBJECT(s), &spi_ops, s,
33929776739SPaolo Bonzini                           "xilinx-spi", R_MAX * 4);
3403efc10e1SAndreas Färber     sysbus_init_mmio(sbd, &s->mmio);
34131e17060SPaolo Bonzini 
34231e17060SPaolo Bonzini     s->irqline = -1;
34331e17060SPaolo Bonzini 
34431e17060SPaolo Bonzini     fifo8_create(&s->tx_fifo, FIFO_CAPACITY);
34531e17060SPaolo Bonzini     fifo8_create(&s->rx_fifo, FIFO_CAPACITY);
34631e17060SPaolo Bonzini 
34731e17060SPaolo Bonzini     return 0;
34831e17060SPaolo Bonzini }
34931e17060SPaolo Bonzini 
35031e17060SPaolo Bonzini static const VMStateDescription vmstate_xilinx_spi = {
35131e17060SPaolo Bonzini     .name = "xilinx_spi",
35231e17060SPaolo Bonzini     .version_id = 1,
35331e17060SPaolo Bonzini     .minimum_version_id = 1,
35431e17060SPaolo Bonzini     .fields = (VMStateField[]) {
35531e17060SPaolo Bonzini         VMSTATE_FIFO8(tx_fifo, XilinxSPI),
35631e17060SPaolo Bonzini         VMSTATE_FIFO8(rx_fifo, XilinxSPI),
35731e17060SPaolo Bonzini         VMSTATE_UINT32_ARRAY(regs, XilinxSPI, R_MAX),
35831e17060SPaolo Bonzini         VMSTATE_END_OF_LIST()
35931e17060SPaolo Bonzini     }
36031e17060SPaolo Bonzini };
36131e17060SPaolo Bonzini 
36231e17060SPaolo Bonzini static Property xilinx_spi_properties[] = {
36331e17060SPaolo Bonzini     DEFINE_PROP_UINT8("num-ss-bits", XilinxSPI, num_cs, 1),
36431e17060SPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
36531e17060SPaolo Bonzini };
36631e17060SPaolo Bonzini 
36731e17060SPaolo Bonzini static void xilinx_spi_class_init(ObjectClass *klass, void *data)
36831e17060SPaolo Bonzini {
36931e17060SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
37031e17060SPaolo Bonzini     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
37131e17060SPaolo Bonzini 
37231e17060SPaolo Bonzini     k->init = xilinx_spi_init;
37331e17060SPaolo Bonzini     dc->reset = xlx_spi_reset;
37431e17060SPaolo Bonzini     dc->props = xilinx_spi_properties;
37531e17060SPaolo Bonzini     dc->vmsd = &vmstate_xilinx_spi;
37631e17060SPaolo Bonzini }
37731e17060SPaolo Bonzini 
37831e17060SPaolo Bonzini static const TypeInfo xilinx_spi_info = {
3793efc10e1SAndreas Färber     .name           = TYPE_XILINX_SPI,
38031e17060SPaolo Bonzini     .parent         = TYPE_SYS_BUS_DEVICE,
38131e17060SPaolo Bonzini     .instance_size  = sizeof(XilinxSPI),
38231e17060SPaolo Bonzini     .class_init     = xilinx_spi_class_init,
38331e17060SPaolo Bonzini };
38431e17060SPaolo Bonzini 
38531e17060SPaolo Bonzini static void xilinx_spi_register_types(void)
38631e17060SPaolo Bonzini {
38731e17060SPaolo Bonzini     type_register_static(&xilinx_spi_info);
38831e17060SPaolo Bonzini }
38931e17060SPaolo Bonzini 
39031e17060SPaolo Bonzini type_init(xilinx_spi_register_types)
391