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