xref: /openbmc/qemu/hw/ssi/xilinx_spi.c (revision 31e17060829f26292d4095c93e3408d740ce6f3d)
1*31e17060SPaolo Bonzini /*
2*31e17060SPaolo Bonzini  * QEMU model of the Xilinx SPI Controller
3*31e17060SPaolo Bonzini  *
4*31e17060SPaolo Bonzini  * Copyright (C) 2010 Edgar E. Iglesias.
5*31e17060SPaolo Bonzini  * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
6*31e17060SPaolo Bonzini  * Copyright (C) 2012 PetaLogix
7*31e17060SPaolo Bonzini  *
8*31e17060SPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
9*31e17060SPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
10*31e17060SPaolo Bonzini  * in the Software without restriction, including without limitation the rights
11*31e17060SPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12*31e17060SPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
13*31e17060SPaolo Bonzini  * furnished to do so, subject to the following conditions:
14*31e17060SPaolo Bonzini  *
15*31e17060SPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
16*31e17060SPaolo Bonzini  * all copies or substantial portions of the Software.
17*31e17060SPaolo Bonzini  *
18*31e17060SPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19*31e17060SPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20*31e17060SPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21*31e17060SPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22*31e17060SPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23*31e17060SPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24*31e17060SPaolo Bonzini  * THE SOFTWARE.
25*31e17060SPaolo Bonzini  */
26*31e17060SPaolo Bonzini 
27*31e17060SPaolo Bonzini #include "hw/sysbus.h"
28*31e17060SPaolo Bonzini #include "sysemu/sysemu.h"
29*31e17060SPaolo Bonzini #include "qemu/log.h"
30*31e17060SPaolo Bonzini #include "qemu/fifo8.h"
31*31e17060SPaolo Bonzini 
32*31e17060SPaolo Bonzini #include "hw/ssi.h"
33*31e17060SPaolo Bonzini 
34*31e17060SPaolo Bonzini #ifdef XILINX_SPI_ERR_DEBUG
35*31e17060SPaolo Bonzini #define DB_PRINT(...) do { \
36*31e17060SPaolo Bonzini     fprintf(stderr,  ": %s: ", __func__); \
37*31e17060SPaolo Bonzini     fprintf(stderr, ## __VA_ARGS__); \
38*31e17060SPaolo Bonzini     } while (0);
39*31e17060SPaolo Bonzini #else
40*31e17060SPaolo Bonzini     #define DB_PRINT(...)
41*31e17060SPaolo Bonzini #endif
42*31e17060SPaolo Bonzini 
43*31e17060SPaolo Bonzini #define R_DGIER     (0x1c / 4)
44*31e17060SPaolo Bonzini #define R_DGIER_IE  (1 << 31)
45*31e17060SPaolo Bonzini 
46*31e17060SPaolo Bonzini #define R_IPISR     (0x20 / 4)
47*31e17060SPaolo Bonzini #define IRQ_DRR_NOT_EMPTY    (1 << (31 - 23))
48*31e17060SPaolo Bonzini #define IRQ_DRR_OVERRUN      (1 << (31 - 26))
49*31e17060SPaolo Bonzini #define IRQ_DRR_FULL         (1 << (31 - 27))
50*31e17060SPaolo Bonzini #define IRQ_TX_FF_HALF_EMPTY (1 << 6)
51*31e17060SPaolo Bonzini #define IRQ_DTR_UNDERRUN     (1 << 3)
52*31e17060SPaolo Bonzini #define IRQ_DTR_EMPTY        (1 << (31 - 29))
53*31e17060SPaolo Bonzini 
54*31e17060SPaolo Bonzini #define R_IPIER     (0x28 / 4)
55*31e17060SPaolo Bonzini #define R_SRR       (0x40 / 4)
56*31e17060SPaolo Bonzini #define R_SPICR     (0x60 / 4)
57*31e17060SPaolo Bonzini #define R_SPICR_TXFF_RST     (1 << 5)
58*31e17060SPaolo Bonzini #define R_SPICR_RXFF_RST     (1 << 6)
59*31e17060SPaolo Bonzini #define R_SPICR_MTI          (1 << 8)
60*31e17060SPaolo Bonzini 
61*31e17060SPaolo Bonzini #define R_SPISR     (0x64 / 4)
62*31e17060SPaolo Bonzini #define SR_TX_FULL    (1 << 3)
63*31e17060SPaolo Bonzini #define SR_TX_EMPTY   (1 << 2)
64*31e17060SPaolo Bonzini #define SR_RX_FULL    (1 << 1)
65*31e17060SPaolo Bonzini #define SR_RX_EMPTY   (1 << 0)
66*31e17060SPaolo Bonzini 
67*31e17060SPaolo Bonzini #define R_SPIDTR    (0x68 / 4)
68*31e17060SPaolo Bonzini #define R_SPIDRR    (0x6C / 4)
69*31e17060SPaolo Bonzini #define R_SPISSR    (0x70 / 4)
70*31e17060SPaolo Bonzini #define R_TX_FF_OCY (0x74 / 4)
71*31e17060SPaolo Bonzini #define R_RX_FF_OCY (0x78 / 4)
72*31e17060SPaolo Bonzini #define R_MAX       (0x7C / 4)
73*31e17060SPaolo Bonzini 
74*31e17060SPaolo Bonzini #define FIFO_CAPACITY 256
75*31e17060SPaolo Bonzini 
76*31e17060SPaolo Bonzini typedef struct XilinxSPI {
77*31e17060SPaolo Bonzini     SysBusDevice busdev;
78*31e17060SPaolo Bonzini     MemoryRegion mmio;
79*31e17060SPaolo Bonzini 
80*31e17060SPaolo Bonzini     qemu_irq irq;
81*31e17060SPaolo Bonzini     int irqline;
82*31e17060SPaolo Bonzini 
83*31e17060SPaolo Bonzini     uint8_t num_cs;
84*31e17060SPaolo Bonzini     qemu_irq *cs_lines;
85*31e17060SPaolo Bonzini 
86*31e17060SPaolo Bonzini     SSIBus *spi;
87*31e17060SPaolo Bonzini 
88*31e17060SPaolo Bonzini     Fifo8 rx_fifo;
89*31e17060SPaolo Bonzini     Fifo8 tx_fifo;
90*31e17060SPaolo Bonzini 
91*31e17060SPaolo Bonzini     uint32_t regs[R_MAX];
92*31e17060SPaolo Bonzini } XilinxSPI;
93*31e17060SPaolo Bonzini 
94*31e17060SPaolo Bonzini static void txfifo_reset(XilinxSPI *s)
95*31e17060SPaolo Bonzini {
96*31e17060SPaolo Bonzini     fifo8_reset(&s->tx_fifo);
97*31e17060SPaolo Bonzini 
98*31e17060SPaolo Bonzini     s->regs[R_SPISR] &= ~SR_TX_FULL;
99*31e17060SPaolo Bonzini     s->regs[R_SPISR] |= SR_TX_EMPTY;
100*31e17060SPaolo Bonzini }
101*31e17060SPaolo Bonzini 
102*31e17060SPaolo Bonzini static void rxfifo_reset(XilinxSPI *s)
103*31e17060SPaolo Bonzini {
104*31e17060SPaolo Bonzini     fifo8_reset(&s->rx_fifo);
105*31e17060SPaolo Bonzini 
106*31e17060SPaolo Bonzini     s->regs[R_SPISR] |= SR_RX_EMPTY;
107*31e17060SPaolo Bonzini     s->regs[R_SPISR] &= ~SR_RX_FULL;
108*31e17060SPaolo Bonzini }
109*31e17060SPaolo Bonzini 
110*31e17060SPaolo Bonzini static void xlx_spi_update_cs(XilinxSPI *s)
111*31e17060SPaolo Bonzini {
112*31e17060SPaolo Bonzini    int i;
113*31e17060SPaolo Bonzini 
114*31e17060SPaolo Bonzini     for (i = 0; i < s->num_cs; ++i) {
115*31e17060SPaolo Bonzini         qemu_set_irq(s->cs_lines[i], !(~s->regs[R_SPISSR] & 1 << i));
116*31e17060SPaolo Bonzini     }
117*31e17060SPaolo Bonzini }
118*31e17060SPaolo Bonzini 
119*31e17060SPaolo Bonzini static void xlx_spi_update_irq(XilinxSPI *s)
120*31e17060SPaolo Bonzini {
121*31e17060SPaolo Bonzini     uint32_t pending;
122*31e17060SPaolo Bonzini 
123*31e17060SPaolo Bonzini     s->regs[R_IPISR] |=
124*31e17060SPaolo Bonzini             (!fifo8_is_empty(&s->rx_fifo) ? IRQ_DRR_NOT_EMPTY : 0) |
125*31e17060SPaolo Bonzini             (fifo8_is_full(&s->rx_fifo) ? IRQ_DRR_FULL : 0);
126*31e17060SPaolo Bonzini 
127*31e17060SPaolo Bonzini     pending = s->regs[R_IPISR] & s->regs[R_IPIER];
128*31e17060SPaolo Bonzini 
129*31e17060SPaolo Bonzini     pending = pending && (s->regs[R_DGIER] & R_DGIER_IE);
130*31e17060SPaolo Bonzini     pending = !!pending;
131*31e17060SPaolo Bonzini 
132*31e17060SPaolo Bonzini     /* This call lies right in the data paths so don't call the
133*31e17060SPaolo Bonzini        irq chain unless things really changed.  */
134*31e17060SPaolo Bonzini     if (pending != s->irqline) {
135*31e17060SPaolo Bonzini         s->irqline = pending;
136*31e17060SPaolo Bonzini         DB_PRINT("irq_change of state %d ISR:%x IER:%X\n",
137*31e17060SPaolo Bonzini                     pending, s->regs[R_IPISR], s->regs[R_IPIER]);
138*31e17060SPaolo Bonzini         qemu_set_irq(s->irq, pending);
139*31e17060SPaolo Bonzini     }
140*31e17060SPaolo Bonzini 
141*31e17060SPaolo Bonzini }
142*31e17060SPaolo Bonzini 
143*31e17060SPaolo Bonzini static void xlx_spi_do_reset(XilinxSPI *s)
144*31e17060SPaolo Bonzini {
145*31e17060SPaolo Bonzini     memset(s->regs, 0, sizeof s->regs);
146*31e17060SPaolo Bonzini 
147*31e17060SPaolo Bonzini     rxfifo_reset(s);
148*31e17060SPaolo Bonzini     txfifo_reset(s);
149*31e17060SPaolo Bonzini 
150*31e17060SPaolo Bonzini     s->regs[R_SPISSR] = ~0;
151*31e17060SPaolo Bonzini     xlx_spi_update_irq(s);
152*31e17060SPaolo Bonzini     xlx_spi_update_cs(s);
153*31e17060SPaolo Bonzini }
154*31e17060SPaolo Bonzini 
155*31e17060SPaolo Bonzini static void xlx_spi_reset(DeviceState *d)
156*31e17060SPaolo Bonzini {
157*31e17060SPaolo Bonzini     xlx_spi_do_reset(DO_UPCAST(XilinxSPI, busdev.qdev, d));
158*31e17060SPaolo Bonzini }
159*31e17060SPaolo Bonzini 
160*31e17060SPaolo Bonzini static inline int spi_master_enabled(XilinxSPI *s)
161*31e17060SPaolo Bonzini {
162*31e17060SPaolo Bonzini     return !(s->regs[R_SPICR] & R_SPICR_MTI);
163*31e17060SPaolo Bonzini }
164*31e17060SPaolo Bonzini 
165*31e17060SPaolo Bonzini static void spi_flush_txfifo(XilinxSPI *s)
166*31e17060SPaolo Bonzini {
167*31e17060SPaolo Bonzini     uint32_t tx;
168*31e17060SPaolo Bonzini     uint32_t rx;
169*31e17060SPaolo Bonzini 
170*31e17060SPaolo Bonzini     while (!fifo8_is_empty(&s->tx_fifo)) {
171*31e17060SPaolo Bonzini         tx = (uint32_t)fifo8_pop(&s->tx_fifo);
172*31e17060SPaolo Bonzini         DB_PRINT("data tx:%x\n", tx);
173*31e17060SPaolo Bonzini         rx = ssi_transfer(s->spi, tx);
174*31e17060SPaolo Bonzini         DB_PRINT("data rx:%x\n", rx);
175*31e17060SPaolo Bonzini         if (fifo8_is_full(&s->rx_fifo)) {
176*31e17060SPaolo Bonzini             s->regs[R_IPISR] |= IRQ_DRR_OVERRUN;
177*31e17060SPaolo Bonzini         } else {
178*31e17060SPaolo Bonzini             fifo8_push(&s->rx_fifo, (uint8_t)rx);
179*31e17060SPaolo Bonzini             if (fifo8_is_full(&s->rx_fifo)) {
180*31e17060SPaolo Bonzini                 s->regs[R_SPISR] |= SR_RX_FULL;
181*31e17060SPaolo Bonzini                 s->regs[R_IPISR] |= IRQ_DRR_FULL;
182*31e17060SPaolo Bonzini             }
183*31e17060SPaolo Bonzini         }
184*31e17060SPaolo Bonzini 
185*31e17060SPaolo Bonzini         s->regs[R_SPISR] &= ~SR_RX_EMPTY;
186*31e17060SPaolo Bonzini         s->regs[R_SPISR] &= ~SR_TX_FULL;
187*31e17060SPaolo Bonzini         s->regs[R_SPISR] |= SR_TX_EMPTY;
188*31e17060SPaolo Bonzini 
189*31e17060SPaolo Bonzini         s->regs[R_IPISR] |= IRQ_DTR_EMPTY;
190*31e17060SPaolo Bonzini         s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY;
191*31e17060SPaolo Bonzini     }
192*31e17060SPaolo Bonzini 
193*31e17060SPaolo Bonzini }
194*31e17060SPaolo Bonzini 
195*31e17060SPaolo Bonzini static uint64_t
196*31e17060SPaolo Bonzini spi_read(void *opaque, hwaddr addr, unsigned int size)
197*31e17060SPaolo Bonzini {
198*31e17060SPaolo Bonzini     XilinxSPI *s = opaque;
199*31e17060SPaolo Bonzini     uint32_t r = 0;
200*31e17060SPaolo Bonzini 
201*31e17060SPaolo Bonzini     addr >>= 2;
202*31e17060SPaolo Bonzini     switch (addr) {
203*31e17060SPaolo Bonzini     case R_SPIDRR:
204*31e17060SPaolo Bonzini         if (fifo8_is_empty(&s->rx_fifo)) {
205*31e17060SPaolo Bonzini             DB_PRINT("Read from empty FIFO!\n");
206*31e17060SPaolo Bonzini             return 0xdeadbeef;
207*31e17060SPaolo Bonzini         }
208*31e17060SPaolo Bonzini 
209*31e17060SPaolo Bonzini         s->regs[R_SPISR] &= ~SR_RX_FULL;
210*31e17060SPaolo Bonzini         r = fifo8_pop(&s->rx_fifo);
211*31e17060SPaolo Bonzini         if (fifo8_is_empty(&s->rx_fifo)) {
212*31e17060SPaolo Bonzini             s->regs[R_SPISR] |= SR_RX_EMPTY;
213*31e17060SPaolo Bonzini         }
214*31e17060SPaolo Bonzini         break;
215*31e17060SPaolo Bonzini 
216*31e17060SPaolo Bonzini     case R_SPISR:
217*31e17060SPaolo Bonzini         r = s->regs[addr];
218*31e17060SPaolo Bonzini         break;
219*31e17060SPaolo Bonzini 
220*31e17060SPaolo Bonzini     default:
221*31e17060SPaolo Bonzini         if (addr < ARRAY_SIZE(s->regs)) {
222*31e17060SPaolo Bonzini             r = s->regs[addr];
223*31e17060SPaolo Bonzini         }
224*31e17060SPaolo Bonzini         break;
225*31e17060SPaolo Bonzini 
226*31e17060SPaolo Bonzini     }
227*31e17060SPaolo Bonzini     DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, r);
228*31e17060SPaolo Bonzini     xlx_spi_update_irq(s);
229*31e17060SPaolo Bonzini     return r;
230*31e17060SPaolo Bonzini }
231*31e17060SPaolo Bonzini 
232*31e17060SPaolo Bonzini static void
233*31e17060SPaolo Bonzini spi_write(void *opaque, hwaddr addr,
234*31e17060SPaolo Bonzini             uint64_t val64, unsigned int size)
235*31e17060SPaolo Bonzini {
236*31e17060SPaolo Bonzini     XilinxSPI *s = opaque;
237*31e17060SPaolo Bonzini     uint32_t value = val64;
238*31e17060SPaolo Bonzini 
239*31e17060SPaolo Bonzini     DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, value);
240*31e17060SPaolo Bonzini     addr >>= 2;
241*31e17060SPaolo Bonzini     switch (addr) {
242*31e17060SPaolo Bonzini     case R_SRR:
243*31e17060SPaolo Bonzini         if (value != 0xa) {
244*31e17060SPaolo Bonzini             DB_PRINT("Invalid write to SRR %x\n", value);
245*31e17060SPaolo Bonzini         } else {
246*31e17060SPaolo Bonzini             xlx_spi_do_reset(s);
247*31e17060SPaolo Bonzini         }
248*31e17060SPaolo Bonzini         break;
249*31e17060SPaolo Bonzini 
250*31e17060SPaolo Bonzini     case R_SPIDTR:
251*31e17060SPaolo Bonzini         s->regs[R_SPISR] &= ~SR_TX_EMPTY;
252*31e17060SPaolo Bonzini         fifo8_push(&s->tx_fifo, (uint8_t)value);
253*31e17060SPaolo Bonzini         if (fifo8_is_full(&s->tx_fifo)) {
254*31e17060SPaolo Bonzini             s->regs[R_SPISR] |= SR_TX_FULL;
255*31e17060SPaolo Bonzini         }
256*31e17060SPaolo Bonzini         if (!spi_master_enabled(s)) {
257*31e17060SPaolo Bonzini             goto done;
258*31e17060SPaolo Bonzini         } else {
259*31e17060SPaolo Bonzini             DB_PRINT("DTR and master enabled\n");
260*31e17060SPaolo Bonzini         }
261*31e17060SPaolo Bonzini         spi_flush_txfifo(s);
262*31e17060SPaolo Bonzini         break;
263*31e17060SPaolo Bonzini 
264*31e17060SPaolo Bonzini     case R_SPISR:
265*31e17060SPaolo Bonzini         DB_PRINT("Invalid write to SPISR %x\n", value);
266*31e17060SPaolo Bonzini         break;
267*31e17060SPaolo Bonzini 
268*31e17060SPaolo Bonzini     case R_IPISR:
269*31e17060SPaolo Bonzini         /* Toggle the bits.  */
270*31e17060SPaolo Bonzini         s->regs[addr] ^= value;
271*31e17060SPaolo Bonzini         break;
272*31e17060SPaolo Bonzini 
273*31e17060SPaolo Bonzini     /* Slave Select Register.  */
274*31e17060SPaolo Bonzini     case R_SPISSR:
275*31e17060SPaolo Bonzini         s->regs[addr] = value;
276*31e17060SPaolo Bonzini         xlx_spi_update_cs(s);
277*31e17060SPaolo Bonzini         break;
278*31e17060SPaolo Bonzini 
279*31e17060SPaolo Bonzini     case R_SPICR:
280*31e17060SPaolo Bonzini         /* FIXME: reset irq and sr state to empty queues.  */
281*31e17060SPaolo Bonzini         if (value & R_SPICR_RXFF_RST) {
282*31e17060SPaolo Bonzini             rxfifo_reset(s);
283*31e17060SPaolo Bonzini         }
284*31e17060SPaolo Bonzini 
285*31e17060SPaolo Bonzini         if (value & R_SPICR_TXFF_RST) {
286*31e17060SPaolo Bonzini             txfifo_reset(s);
287*31e17060SPaolo Bonzini         }
288*31e17060SPaolo Bonzini         value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST);
289*31e17060SPaolo Bonzini         s->regs[addr] = value;
290*31e17060SPaolo Bonzini 
291*31e17060SPaolo Bonzini         if (!(value & R_SPICR_MTI)) {
292*31e17060SPaolo Bonzini             spi_flush_txfifo(s);
293*31e17060SPaolo Bonzini         }
294*31e17060SPaolo Bonzini         break;
295*31e17060SPaolo Bonzini 
296*31e17060SPaolo Bonzini     default:
297*31e17060SPaolo Bonzini         if (addr < ARRAY_SIZE(s->regs)) {
298*31e17060SPaolo Bonzini             s->regs[addr] = value;
299*31e17060SPaolo Bonzini         }
300*31e17060SPaolo Bonzini         break;
301*31e17060SPaolo Bonzini     }
302*31e17060SPaolo Bonzini 
303*31e17060SPaolo Bonzini done:
304*31e17060SPaolo Bonzini     xlx_spi_update_irq(s);
305*31e17060SPaolo Bonzini }
306*31e17060SPaolo Bonzini 
307*31e17060SPaolo Bonzini static const MemoryRegionOps spi_ops = {
308*31e17060SPaolo Bonzini     .read = spi_read,
309*31e17060SPaolo Bonzini     .write = spi_write,
310*31e17060SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
311*31e17060SPaolo Bonzini     .valid = {
312*31e17060SPaolo Bonzini         .min_access_size = 4,
313*31e17060SPaolo Bonzini         .max_access_size = 4
314*31e17060SPaolo Bonzini     }
315*31e17060SPaolo Bonzini };
316*31e17060SPaolo Bonzini 
317*31e17060SPaolo Bonzini static int xilinx_spi_init(SysBusDevice *dev)
318*31e17060SPaolo Bonzini {
319*31e17060SPaolo Bonzini     int i;
320*31e17060SPaolo Bonzini     XilinxSPI *s = FROM_SYSBUS(typeof(*s), dev);
321*31e17060SPaolo Bonzini 
322*31e17060SPaolo Bonzini     DB_PRINT("\n");
323*31e17060SPaolo Bonzini 
324*31e17060SPaolo Bonzini     s->spi = ssi_create_bus(&dev->qdev, "spi");
325*31e17060SPaolo Bonzini 
326*31e17060SPaolo Bonzini     sysbus_init_irq(dev, &s->irq);
327*31e17060SPaolo Bonzini     s->cs_lines = g_new(qemu_irq, s->num_cs);
328*31e17060SPaolo Bonzini     ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi);
329*31e17060SPaolo Bonzini     for (i = 0; i < s->num_cs; ++i) {
330*31e17060SPaolo Bonzini         sysbus_init_irq(dev, &s->cs_lines[i]);
331*31e17060SPaolo Bonzini     }
332*31e17060SPaolo Bonzini 
333*31e17060SPaolo Bonzini     memory_region_init_io(&s->mmio, &spi_ops, s, "xilinx-spi", R_MAX * 4);
334*31e17060SPaolo Bonzini     sysbus_init_mmio(dev, &s->mmio);
335*31e17060SPaolo Bonzini 
336*31e17060SPaolo Bonzini     s->irqline = -1;
337*31e17060SPaolo Bonzini 
338*31e17060SPaolo Bonzini     fifo8_create(&s->tx_fifo, FIFO_CAPACITY);
339*31e17060SPaolo Bonzini     fifo8_create(&s->rx_fifo, FIFO_CAPACITY);
340*31e17060SPaolo Bonzini 
341*31e17060SPaolo Bonzini     return 0;
342*31e17060SPaolo Bonzini }
343*31e17060SPaolo Bonzini 
344*31e17060SPaolo Bonzini static const VMStateDescription vmstate_xilinx_spi = {
345*31e17060SPaolo Bonzini     .name = "xilinx_spi",
346*31e17060SPaolo Bonzini     .version_id = 1,
347*31e17060SPaolo Bonzini     .minimum_version_id = 1,
348*31e17060SPaolo Bonzini     .minimum_version_id_old = 1,
349*31e17060SPaolo Bonzini     .fields = (VMStateField[]) {
350*31e17060SPaolo Bonzini         VMSTATE_FIFO8(tx_fifo, XilinxSPI),
351*31e17060SPaolo Bonzini         VMSTATE_FIFO8(rx_fifo, XilinxSPI),
352*31e17060SPaolo Bonzini         VMSTATE_UINT32_ARRAY(regs, XilinxSPI, R_MAX),
353*31e17060SPaolo Bonzini         VMSTATE_END_OF_LIST()
354*31e17060SPaolo Bonzini     }
355*31e17060SPaolo Bonzini };
356*31e17060SPaolo Bonzini 
357*31e17060SPaolo Bonzini static Property xilinx_spi_properties[] = {
358*31e17060SPaolo Bonzini     DEFINE_PROP_UINT8("num-ss-bits", XilinxSPI, num_cs, 1),
359*31e17060SPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
360*31e17060SPaolo Bonzini };
361*31e17060SPaolo Bonzini 
362*31e17060SPaolo Bonzini static void xilinx_spi_class_init(ObjectClass *klass, void *data)
363*31e17060SPaolo Bonzini {
364*31e17060SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
365*31e17060SPaolo Bonzini     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
366*31e17060SPaolo Bonzini 
367*31e17060SPaolo Bonzini     k->init = xilinx_spi_init;
368*31e17060SPaolo Bonzini     dc->reset = xlx_spi_reset;
369*31e17060SPaolo Bonzini     dc->props = xilinx_spi_properties;
370*31e17060SPaolo Bonzini     dc->vmsd = &vmstate_xilinx_spi;
371*31e17060SPaolo Bonzini }
372*31e17060SPaolo Bonzini 
373*31e17060SPaolo Bonzini static const TypeInfo xilinx_spi_info = {
374*31e17060SPaolo Bonzini     .name           = "xlnx.xps-spi",
375*31e17060SPaolo Bonzini     .parent         = TYPE_SYS_BUS_DEVICE,
376*31e17060SPaolo Bonzini     .instance_size  = sizeof(XilinxSPI),
377*31e17060SPaolo Bonzini     .class_init     = xilinx_spi_class_init,
378*31e17060SPaolo Bonzini };
379*31e17060SPaolo Bonzini 
380*31e17060SPaolo Bonzini static void xilinx_spi_register_types(void)
381*31e17060SPaolo Bonzini {
382*31e17060SPaolo Bonzini     type_register_static(&xilinx_spi_info);
383*31e17060SPaolo Bonzini }
384*31e17060SPaolo Bonzini 
385*31e17060SPaolo Bonzini type_init(xilinx_spi_register_types)
386