xref: /qemu/hw/ssi/xilinx_spi.c (revision 883f2c591fee552067e160208b4fe0228dbabbb1)
1929d1b52SPeter A. G. Crosthwaite /*
2929d1b52SPeter A. G. Crosthwaite  * QEMU model of the Xilinx SPI Controller
3929d1b52SPeter A. G. Crosthwaite  *
4929d1b52SPeter A. G. Crosthwaite  * Copyright (C) 2010 Edgar E. Iglesias.
5929d1b52SPeter A. G. Crosthwaite  * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
6929d1b52SPeter A. G. Crosthwaite  * Copyright (C) 2012 PetaLogix
7929d1b52SPeter A. G. Crosthwaite  *
8929d1b52SPeter A. G. Crosthwaite  * Permission is hereby granted, free of charge, to any person obtaining a copy
9929d1b52SPeter A. G. Crosthwaite  * of this software and associated documentation files (the "Software"), to deal
10929d1b52SPeter A. G. Crosthwaite  * in the Software without restriction, including without limitation the rights
11929d1b52SPeter A. G. Crosthwaite  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12929d1b52SPeter A. G. Crosthwaite  * copies of the Software, and to permit persons to whom the Software is
13929d1b52SPeter A. G. Crosthwaite  * furnished to do so, subject to the following conditions:
14929d1b52SPeter A. G. Crosthwaite  *
15929d1b52SPeter A. G. Crosthwaite  * The above copyright notice and this permission notice shall be included in
16929d1b52SPeter A. G. Crosthwaite  * all copies or substantial portions of the Software.
17929d1b52SPeter A. G. Crosthwaite  *
18929d1b52SPeter A. G. Crosthwaite  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19929d1b52SPeter A. G. Crosthwaite  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20929d1b52SPeter A. G. Crosthwaite  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21929d1b52SPeter A. G. Crosthwaite  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22929d1b52SPeter A. G. Crosthwaite  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23929d1b52SPeter A. G. Crosthwaite  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24929d1b52SPeter A. G. Crosthwaite  * THE SOFTWARE.
25929d1b52SPeter A. G. Crosthwaite  */
26929d1b52SPeter A. G. Crosthwaite 
278ef94f0bSPeter Maydell #include "qemu/osdep.h"
2883c9f4caSPaolo Bonzini #include "hw/sysbus.h"
29d6454270SMarkus Armbruster #include "migration/vmstate.h"
300b8fa32fSMarkus Armbruster #include "qemu/module.h"
31fd7f0d66SPaolo Bonzini #include "qemu/fifo8.h"
32929d1b52SPeter A. G. Crosthwaite 
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"
37929d1b52SPeter A. G. Crosthwaite 
38929d1b52SPeter A. G. Crosthwaite #ifdef XILINX_SPI_ERR_DEBUG
39929d1b52SPeter A. G. Crosthwaite #define DB_PRINT(...) do { \
40929d1b52SPeter A. G. Crosthwaite     fprintf(stderr,  ": %s: ", __func__); \
41929d1b52SPeter A. G. Crosthwaite     fprintf(stderr, ## __VA_ARGS__); \
422562755eSEric Blake     } while (0)
43929d1b52SPeter A. G. Crosthwaite #else
44929d1b52SPeter A. G. Crosthwaite     #define DB_PRINT(...)
45929d1b52SPeter A. G. Crosthwaite #endif
46929d1b52SPeter A. G. Crosthwaite 
47929d1b52SPeter A. G. Crosthwaite #define R_DGIER     (0x1c / 4)
48929d1b52SPeter A. G. Crosthwaite #define R_DGIER_IE  (1 << 31)
49929d1b52SPeter A. G. Crosthwaite 
50929d1b52SPeter A. G. Crosthwaite #define R_IPISR     (0x20 / 4)
51929d1b52SPeter A. G. Crosthwaite #define IRQ_DRR_NOT_EMPTY    (1 << (31 - 23))
52929d1b52SPeter A. G. Crosthwaite #define IRQ_DRR_OVERRUN      (1 << (31 - 26))
53929d1b52SPeter A. G. Crosthwaite #define IRQ_DRR_FULL         (1 << (31 - 27))
54929d1b52SPeter A. G. Crosthwaite #define IRQ_TX_FF_HALF_EMPTY (1 << 6)
55929d1b52SPeter A. G. Crosthwaite #define IRQ_DTR_UNDERRUN     (1 << 3)
56929d1b52SPeter A. G. Crosthwaite #define IRQ_DTR_EMPTY        (1 << (31 - 29))
57929d1b52SPeter A. G. Crosthwaite 
58929d1b52SPeter A. G. Crosthwaite #define R_IPIER     (0x28 / 4)
59929d1b52SPeter A. G. Crosthwaite #define R_SRR       (0x40 / 4)
60929d1b52SPeter A. G. Crosthwaite #define R_SPICR     (0x60 / 4)
61929d1b52SPeter A. G. Crosthwaite #define R_SPICR_TXFF_RST     (1 << 5)
62929d1b52SPeter A. G. Crosthwaite #define R_SPICR_RXFF_RST     (1 << 6)
63929d1b52SPeter A. G. Crosthwaite #define R_SPICR_MTI          (1 << 8)
64929d1b52SPeter A. G. Crosthwaite 
65929d1b52SPeter A. G. Crosthwaite #define R_SPISR     (0x64 / 4)
66929d1b52SPeter A. G. Crosthwaite #define SR_TX_FULL    (1 << 3)
67929d1b52SPeter A. G. Crosthwaite #define SR_TX_EMPTY   (1 << 2)
68929d1b52SPeter A. G. Crosthwaite #define SR_RX_FULL    (1 << 1)
69929d1b52SPeter A. G. Crosthwaite #define SR_RX_EMPTY   (1 << 0)
70929d1b52SPeter A. G. Crosthwaite 
71929d1b52SPeter A. G. Crosthwaite #define R_SPIDTR    (0x68 / 4)
72929d1b52SPeter A. G. Crosthwaite #define R_SPIDRR    (0x6C / 4)
73929d1b52SPeter A. G. Crosthwaite #define R_SPISSR    (0x70 / 4)
74929d1b52SPeter A. G. Crosthwaite #define R_TX_FF_OCY (0x74 / 4)
75929d1b52SPeter A. G. Crosthwaite #define R_RX_FF_OCY (0x78 / 4)
76929d1b52SPeter A. G. Crosthwaite #define R_MAX       (0x7C / 4)
77929d1b52SPeter A. G. Crosthwaite 
78929d1b52SPeter A. G. Crosthwaite #define FIFO_CAPACITY 256
79929d1b52SPeter A. G. Crosthwaite 
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 
86929d1b52SPeter A. G. Crosthwaite     MemoryRegion mmio;
87929d1b52SPeter A. G. Crosthwaite 
88929d1b52SPeter A. G. Crosthwaite     qemu_irq irq;
89929d1b52SPeter A. G. Crosthwaite     int irqline;
90929d1b52SPeter A. G. Crosthwaite 
91929d1b52SPeter A. G. Crosthwaite     uint8_t num_cs;
92929d1b52SPeter A. G. Crosthwaite     qemu_irq *cs_lines;
93929d1b52SPeter A. G. Crosthwaite 
94929d1b52SPeter A. G. Crosthwaite     SSIBus *spi;
95929d1b52SPeter A. G. Crosthwaite 
96929d1b52SPeter A. G. Crosthwaite     Fifo8 rx_fifo;
97929d1b52SPeter A. G. Crosthwaite     Fifo8 tx_fifo;
98929d1b52SPeter A. G. Crosthwaite 
99929d1b52SPeter A. G. Crosthwaite     uint32_t regs[R_MAX];
100db1015e9SEduardo Habkost };
101929d1b52SPeter A. G. Crosthwaite 
102929d1b52SPeter A. G. Crosthwaite static void txfifo_reset(XilinxSPI *s)
103929d1b52SPeter A. G. Crosthwaite {
104929d1b52SPeter A. G. Crosthwaite     fifo8_reset(&s->tx_fifo);
105929d1b52SPeter A. G. Crosthwaite 
106929d1b52SPeter A. G. Crosthwaite     s->regs[R_SPISR] &= ~SR_TX_FULL;
107929d1b52SPeter A. G. Crosthwaite     s->regs[R_SPISR] |= SR_TX_EMPTY;
108929d1b52SPeter A. G. Crosthwaite }
109929d1b52SPeter A. G. Crosthwaite 
110929d1b52SPeter A. G. Crosthwaite static void rxfifo_reset(XilinxSPI *s)
111929d1b52SPeter A. G. Crosthwaite {
112929d1b52SPeter A. G. Crosthwaite     fifo8_reset(&s->rx_fifo);
113929d1b52SPeter A. G. Crosthwaite 
114929d1b52SPeter A. G. Crosthwaite     s->regs[R_SPISR] |= SR_RX_EMPTY;
115929d1b52SPeter A. G. Crosthwaite     s->regs[R_SPISR] &= ~SR_RX_FULL;
116929d1b52SPeter A. G. Crosthwaite }
117929d1b52SPeter A. G. Crosthwaite 
118929d1b52SPeter A. G. Crosthwaite static void xlx_spi_update_cs(XilinxSPI *s)
119929d1b52SPeter A. G. Crosthwaite {
120929d1b52SPeter A. G. Crosthwaite     int i;
121929d1b52SPeter A. G. Crosthwaite 
122929d1b52SPeter A. G. Crosthwaite     for (i = 0; i < s->num_cs; ++i) {
123929d1b52SPeter A. G. Crosthwaite         qemu_set_irq(s->cs_lines[i], !(~s->regs[R_SPISSR] & 1 << i));
124929d1b52SPeter A. G. Crosthwaite     }
125929d1b52SPeter A. G. Crosthwaite }
126929d1b52SPeter A. G. Crosthwaite 
127929d1b52SPeter A. G. Crosthwaite static void xlx_spi_update_irq(XilinxSPI *s)
128929d1b52SPeter A. G. Crosthwaite {
129929d1b52SPeter A. G. Crosthwaite     uint32_t pending;
130929d1b52SPeter A. G. Crosthwaite 
131929d1b52SPeter A. G. Crosthwaite     s->regs[R_IPISR] |=
132929d1b52SPeter A. G. Crosthwaite             (!fifo8_is_empty(&s->rx_fifo) ? IRQ_DRR_NOT_EMPTY : 0) |
133929d1b52SPeter A. G. Crosthwaite             (fifo8_is_full(&s->rx_fifo) ? IRQ_DRR_FULL : 0);
134929d1b52SPeter A. G. Crosthwaite 
135929d1b52SPeter A. G. Crosthwaite     pending = s->regs[R_IPISR] & s->regs[R_IPIER];
136929d1b52SPeter A. G. Crosthwaite 
137929d1b52SPeter A. G. Crosthwaite     pending = pending && (s->regs[R_DGIER] & R_DGIER_IE);
138929d1b52SPeter A. G. Crosthwaite     pending = !!pending;
139929d1b52SPeter A. G. Crosthwaite 
140929d1b52SPeter A. G. Crosthwaite     /* This call lies right in the data paths so don't call the
141929d1b52SPeter A. G. Crosthwaite        irq chain unless things really changed.  */
142929d1b52SPeter A. G. Crosthwaite     if (pending != s->irqline) {
143929d1b52SPeter A. G. Crosthwaite         s->irqline = pending;
1449df0a972SAlexChen         DB_PRINT("irq_change of state %u ISR:%x IER:%X\n",
145929d1b52SPeter A. G. Crosthwaite                     pending, s->regs[R_IPISR], s->regs[R_IPIER]);
146929d1b52SPeter A. G. Crosthwaite         qemu_set_irq(s->irq, pending);
147929d1b52SPeter A. G. Crosthwaite     }
148929d1b52SPeter A. G. Crosthwaite 
149929d1b52SPeter A. G. Crosthwaite }
150929d1b52SPeter A. G. Crosthwaite 
151929d1b52SPeter A. G. Crosthwaite static void xlx_spi_do_reset(XilinxSPI *s)
152929d1b52SPeter A. G. Crosthwaite {
153929d1b52SPeter A. G. Crosthwaite     memset(s->regs, 0, sizeof s->regs);
154929d1b52SPeter A. G. Crosthwaite 
155929d1b52SPeter A. G. Crosthwaite     rxfifo_reset(s);
156929d1b52SPeter A. G. Crosthwaite     txfifo_reset(s);
157929d1b52SPeter A. G. Crosthwaite 
158929d1b52SPeter A. G. Crosthwaite     s->regs[R_SPISSR] = ~0;
159929d1b52SPeter A. G. Crosthwaite     xlx_spi_update_irq(s);
160929d1b52SPeter A. G. Crosthwaite     xlx_spi_update_cs(s);
161929d1b52SPeter A. G. Crosthwaite }
162929d1b52SPeter A. G. Crosthwaite 
163929d1b52SPeter A. G. Crosthwaite static void xlx_spi_reset(DeviceState *d)
164929d1b52SPeter A. G. Crosthwaite {
1653efc10e1SAndreas Färber     xlx_spi_do_reset(XILINX_SPI(d));
166929d1b52SPeter A. G. Crosthwaite }
167929d1b52SPeter A. G. Crosthwaite 
168929d1b52SPeter A. G. Crosthwaite static inline int spi_master_enabled(XilinxSPI *s)
169929d1b52SPeter A. G. Crosthwaite {
170929d1b52SPeter A. G. Crosthwaite     return !(s->regs[R_SPICR] & R_SPICR_MTI);
171929d1b52SPeter A. G. Crosthwaite }
172929d1b52SPeter A. G. Crosthwaite 
173929d1b52SPeter A. G. Crosthwaite static void spi_flush_txfifo(XilinxSPI *s)
174929d1b52SPeter A. G. Crosthwaite {
175929d1b52SPeter A. G. Crosthwaite     uint32_t tx;
176929d1b52SPeter A. G. Crosthwaite     uint32_t rx;
177929d1b52SPeter A. G. Crosthwaite 
178929d1b52SPeter A. G. Crosthwaite     while (!fifo8_is_empty(&s->tx_fifo)) {
179929d1b52SPeter A. G. Crosthwaite         tx = (uint32_t)fifo8_pop(&s->tx_fifo);
180929d1b52SPeter A. G. Crosthwaite         DB_PRINT("data tx:%x\n", tx);
181929d1b52SPeter A. G. Crosthwaite         rx = ssi_transfer(s->spi, tx);
182929d1b52SPeter A. G. Crosthwaite         DB_PRINT("data rx:%x\n", rx);
183929d1b52SPeter A. G. Crosthwaite         if (fifo8_is_full(&s->rx_fifo)) {
184929d1b52SPeter A. G. Crosthwaite             s->regs[R_IPISR] |= IRQ_DRR_OVERRUN;
185929d1b52SPeter A. G. Crosthwaite         } else {
186929d1b52SPeter A. G. Crosthwaite             fifo8_push(&s->rx_fifo, (uint8_t)rx);
187929d1b52SPeter A. G. Crosthwaite             if (fifo8_is_full(&s->rx_fifo)) {
188929d1b52SPeter A. G. Crosthwaite                 s->regs[R_SPISR] |= SR_RX_FULL;
189929d1b52SPeter A. G. Crosthwaite                 s->regs[R_IPISR] |= IRQ_DRR_FULL;
190929d1b52SPeter A. G. Crosthwaite             }
191929d1b52SPeter A. G. Crosthwaite         }
192929d1b52SPeter A. G. Crosthwaite 
193929d1b52SPeter A. G. Crosthwaite         s->regs[R_SPISR] &= ~SR_RX_EMPTY;
194929d1b52SPeter A. G. Crosthwaite         s->regs[R_SPISR] &= ~SR_TX_FULL;
195929d1b52SPeter A. G. Crosthwaite         s->regs[R_SPISR] |= SR_TX_EMPTY;
196929d1b52SPeter A. G. Crosthwaite 
197929d1b52SPeter A. G. Crosthwaite         s->regs[R_IPISR] |= IRQ_DTR_EMPTY;
198929d1b52SPeter A. G. Crosthwaite         s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY;
199929d1b52SPeter A. G. Crosthwaite     }
200929d1b52SPeter A. G. Crosthwaite 
201929d1b52SPeter A. G. Crosthwaite }
202929d1b52SPeter A. G. Crosthwaite 
203929d1b52SPeter A. G. Crosthwaite static uint64_t
204a8170e5eSAvi Kivity spi_read(void *opaque, hwaddr addr, unsigned int size)
205929d1b52SPeter A. G. Crosthwaite {
206929d1b52SPeter A. G. Crosthwaite     XilinxSPI *s = opaque;
207929d1b52SPeter A. G. Crosthwaite     uint32_t r = 0;
208929d1b52SPeter A. G. Crosthwaite 
209929d1b52SPeter A. G. Crosthwaite     addr >>= 2;
210929d1b52SPeter A. G. Crosthwaite     switch (addr) {
211929d1b52SPeter A. G. Crosthwaite     case R_SPIDRR:
212929d1b52SPeter A. G. Crosthwaite         if (fifo8_is_empty(&s->rx_fifo)) {
213929d1b52SPeter A. G. Crosthwaite             DB_PRINT("Read from empty FIFO!\n");
214929d1b52SPeter A. G. Crosthwaite             return 0xdeadbeef;
215929d1b52SPeter A. G. Crosthwaite         }
216929d1b52SPeter A. G. Crosthwaite 
217929d1b52SPeter A. G. Crosthwaite         s->regs[R_SPISR] &= ~SR_RX_FULL;
218929d1b52SPeter A. G. Crosthwaite         r = fifo8_pop(&s->rx_fifo);
219929d1b52SPeter A. G. Crosthwaite         if (fifo8_is_empty(&s->rx_fifo)) {
220929d1b52SPeter A. G. Crosthwaite             s->regs[R_SPISR] |= SR_RX_EMPTY;
221929d1b52SPeter A. G. Crosthwaite         }
222929d1b52SPeter A. G. Crosthwaite         break;
223929d1b52SPeter A. G. Crosthwaite 
224929d1b52SPeter A. G. Crosthwaite     case R_SPISR:
225929d1b52SPeter A. G. Crosthwaite         r = s->regs[addr];
226929d1b52SPeter A. G. Crosthwaite         break;
227929d1b52SPeter A. G. Crosthwaite 
228929d1b52SPeter A. G. Crosthwaite     default:
229929d1b52SPeter A. G. Crosthwaite         if (addr < ARRAY_SIZE(s->regs)) {
230929d1b52SPeter A. G. Crosthwaite             r = s->regs[addr];
231929d1b52SPeter A. G. Crosthwaite         }
232929d1b52SPeter A. G. Crosthwaite         break;
233929d1b52SPeter A. G. Crosthwaite 
234929d1b52SPeter A. G. Crosthwaite     }
235*883f2c59SPhilippe Mathieu-Daudé     DB_PRINT("addr=" HWADDR_FMT_plx " = %x\n", addr * 4, r);
236929d1b52SPeter A. G. Crosthwaite     xlx_spi_update_irq(s);
237929d1b52SPeter A. G. Crosthwaite     return r;
238929d1b52SPeter A. G. Crosthwaite }
239929d1b52SPeter A. G. Crosthwaite 
240929d1b52SPeter A. G. Crosthwaite static void
241a8170e5eSAvi Kivity spi_write(void *opaque, hwaddr addr,
242929d1b52SPeter A. G. Crosthwaite             uint64_t val64, unsigned int size)
243929d1b52SPeter A. G. Crosthwaite {
244929d1b52SPeter A. G. Crosthwaite     XilinxSPI *s = opaque;
245929d1b52SPeter A. G. Crosthwaite     uint32_t value = val64;
246929d1b52SPeter A. G. Crosthwaite 
247*883f2c59SPhilippe Mathieu-Daudé     DB_PRINT("addr=" HWADDR_FMT_plx " = %x\n", addr, value);
248929d1b52SPeter A. G. Crosthwaite     addr >>= 2;
249929d1b52SPeter A. G. Crosthwaite     switch (addr) {
250929d1b52SPeter A. G. Crosthwaite     case R_SRR:
251929d1b52SPeter A. G. Crosthwaite         if (value != 0xa) {
252929d1b52SPeter A. G. Crosthwaite             DB_PRINT("Invalid write to SRR %x\n", value);
253929d1b52SPeter A. G. Crosthwaite         } else {
254929d1b52SPeter A. G. Crosthwaite             xlx_spi_do_reset(s);
255929d1b52SPeter A. G. Crosthwaite         }
256929d1b52SPeter A. G. Crosthwaite         break;
257929d1b52SPeter A. G. Crosthwaite 
258929d1b52SPeter A. G. Crosthwaite     case R_SPIDTR:
259929d1b52SPeter A. G. Crosthwaite         s->regs[R_SPISR] &= ~SR_TX_EMPTY;
260929d1b52SPeter A. G. Crosthwaite         fifo8_push(&s->tx_fifo, (uint8_t)value);
261929d1b52SPeter A. G. Crosthwaite         if (fifo8_is_full(&s->tx_fifo)) {
262929d1b52SPeter A. G. Crosthwaite             s->regs[R_SPISR] |= SR_TX_FULL;
263929d1b52SPeter A. G. Crosthwaite         }
264929d1b52SPeter A. G. Crosthwaite         if (!spi_master_enabled(s)) {
265929d1b52SPeter A. G. Crosthwaite             goto done;
266929d1b52SPeter A. G. Crosthwaite         } else {
267929d1b52SPeter A. G. Crosthwaite             DB_PRINT("DTR and master enabled\n");
268929d1b52SPeter A. G. Crosthwaite         }
269929d1b52SPeter A. G. Crosthwaite         spi_flush_txfifo(s);
270929d1b52SPeter A. G. Crosthwaite         break;
271929d1b52SPeter A. G. Crosthwaite 
272929d1b52SPeter A. G. Crosthwaite     case R_SPISR:
273929d1b52SPeter A. G. Crosthwaite         DB_PRINT("Invalid write to SPISR %x\n", value);
274929d1b52SPeter A. G. Crosthwaite         break;
275929d1b52SPeter A. G. Crosthwaite 
276929d1b52SPeter A. G. Crosthwaite     case R_IPISR:
277929d1b52SPeter A. G. Crosthwaite         /* Toggle the bits.  */
278929d1b52SPeter A. G. Crosthwaite         s->regs[addr] ^= value;
279929d1b52SPeter A. G. Crosthwaite         break;
280929d1b52SPeter A. G. Crosthwaite 
281929d1b52SPeter A. G. Crosthwaite     /* Slave Select Register.  */
282929d1b52SPeter A. G. Crosthwaite     case R_SPISSR:
283929d1b52SPeter A. G. Crosthwaite         s->regs[addr] = value;
284929d1b52SPeter A. G. Crosthwaite         xlx_spi_update_cs(s);
285929d1b52SPeter A. G. Crosthwaite         break;
286929d1b52SPeter A. G. Crosthwaite 
287929d1b52SPeter A. G. Crosthwaite     case R_SPICR:
288929d1b52SPeter A. G. Crosthwaite         /* FIXME: reset irq and sr state to empty queues.  */
289929d1b52SPeter A. G. Crosthwaite         if (value & R_SPICR_RXFF_RST) {
290929d1b52SPeter A. G. Crosthwaite             rxfifo_reset(s);
291929d1b52SPeter A. G. Crosthwaite         }
292929d1b52SPeter A. G. Crosthwaite 
293929d1b52SPeter A. G. Crosthwaite         if (value & R_SPICR_TXFF_RST) {
294929d1b52SPeter A. G. Crosthwaite             txfifo_reset(s);
295929d1b52SPeter A. G. Crosthwaite         }
296929d1b52SPeter A. G. Crosthwaite         value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST);
297929d1b52SPeter A. G. Crosthwaite         s->regs[addr] = value;
298929d1b52SPeter A. G. Crosthwaite 
299929d1b52SPeter A. G. Crosthwaite         if (!(value & R_SPICR_MTI)) {
300929d1b52SPeter A. G. Crosthwaite             spi_flush_txfifo(s);
301929d1b52SPeter A. G. Crosthwaite         }
302929d1b52SPeter A. G. Crosthwaite         break;
303929d1b52SPeter A. G. Crosthwaite 
304929d1b52SPeter A. G. Crosthwaite     default:
305929d1b52SPeter A. G. Crosthwaite         if (addr < ARRAY_SIZE(s->regs)) {
306929d1b52SPeter A. G. Crosthwaite             s->regs[addr] = value;
307929d1b52SPeter A. G. Crosthwaite         }
308929d1b52SPeter A. G. Crosthwaite         break;
309929d1b52SPeter A. G. Crosthwaite     }
310929d1b52SPeter A. G. Crosthwaite 
311929d1b52SPeter A. G. Crosthwaite done:
312929d1b52SPeter A. G. Crosthwaite     xlx_spi_update_irq(s);
313929d1b52SPeter A. G. Crosthwaite }
314929d1b52SPeter A. G. Crosthwaite 
315929d1b52SPeter A. G. Crosthwaite static const MemoryRegionOps spi_ops = {
316929d1b52SPeter A. G. Crosthwaite     .read = spi_read,
317929d1b52SPeter A. G. Crosthwaite     .write = spi_write,
318929d1b52SPeter A. G. Crosthwaite     .endianness = DEVICE_NATIVE_ENDIAN,
319929d1b52SPeter A. G. Crosthwaite     .valid = {
320929d1b52SPeter A. G. Crosthwaite         .min_access_size = 4,
321929d1b52SPeter A. G. Crosthwaite         .max_access_size = 4
322929d1b52SPeter A. G. Crosthwaite     }
323929d1b52SPeter A. G. Crosthwaite };
324929d1b52SPeter A. G. Crosthwaite 
325a7e1562cSPhilippe Mathieu-Daudé static void xilinx_spi_realize(DeviceState *dev, Error **errp)
326929d1b52SPeter A. G. Crosthwaite {
327a7e1562cSPhilippe Mathieu-Daudé     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
3283efc10e1SAndreas Färber     XilinxSPI *s = XILINX_SPI(dev);
329929d1b52SPeter A. G. Crosthwaite     int i;
330929d1b52SPeter A. G. Crosthwaite 
331929d1b52SPeter A. G. Crosthwaite     DB_PRINT("\n");
332b4ae3cfaSPeter Crosthwaite 
3333efc10e1SAndreas Färber     s->spi = ssi_create_bus(dev, "spi");
334b4ae3cfaSPeter Crosthwaite 
3353efc10e1SAndreas Färber     sysbus_init_irq(sbd, &s->irq);
336c75f3c04SPeter Crosthwaite     s->cs_lines = g_new0(qemu_irq, s->num_cs);
337929d1b52SPeter A. G. Crosthwaite     for (i = 0; i < s->num_cs; ++i) {
3383efc10e1SAndreas Färber         sysbus_init_irq(sbd, &s->cs_lines[i]);
339929d1b52SPeter A. G. Crosthwaite     }
340929d1b52SPeter A. G. Crosthwaite 
34129776739SPaolo Bonzini     memory_region_init_io(&s->mmio, OBJECT(s), &spi_ops, s,
34229776739SPaolo Bonzini                           "xilinx-spi", R_MAX * 4);
3433efc10e1SAndreas Färber     sysbus_init_mmio(sbd, &s->mmio);
344929d1b52SPeter A. G. Crosthwaite 
345929d1b52SPeter A. G. Crosthwaite     s->irqline = -1;
346929d1b52SPeter A. G. Crosthwaite 
347929d1b52SPeter A. G. Crosthwaite     fifo8_create(&s->tx_fifo, FIFO_CAPACITY);
348929d1b52SPeter A. G. Crosthwaite     fifo8_create(&s->rx_fifo, FIFO_CAPACITY);
349929d1b52SPeter A. G. Crosthwaite }
350929d1b52SPeter A. G. Crosthwaite 
351929d1b52SPeter A. G. Crosthwaite static const VMStateDescription vmstate_xilinx_spi = {
352929d1b52SPeter A. G. Crosthwaite     .name = "xilinx_spi",
353929d1b52SPeter A. G. Crosthwaite     .version_id = 1,
354929d1b52SPeter A. G. Crosthwaite     .minimum_version_id = 1,
355929d1b52SPeter A. G. Crosthwaite     .fields = (VMStateField[]) {
356929d1b52SPeter A. G. Crosthwaite         VMSTATE_FIFO8(tx_fifo, XilinxSPI),
357929d1b52SPeter A. G. Crosthwaite         VMSTATE_FIFO8(rx_fifo, XilinxSPI),
358929d1b52SPeter A. G. Crosthwaite         VMSTATE_UINT32_ARRAY(regs, XilinxSPI, R_MAX),
359929d1b52SPeter A. G. Crosthwaite         VMSTATE_END_OF_LIST()
360929d1b52SPeter A. G. Crosthwaite     }
361929d1b52SPeter A. G. Crosthwaite };
362929d1b52SPeter A. G. Crosthwaite 
363929d1b52SPeter A. G. Crosthwaite static Property xilinx_spi_properties[] = {
364929d1b52SPeter A. G. Crosthwaite     DEFINE_PROP_UINT8("num-ss-bits", XilinxSPI, num_cs, 1),
365929d1b52SPeter A. G. Crosthwaite     DEFINE_PROP_END_OF_LIST(),
366929d1b52SPeter A. G. Crosthwaite };
367929d1b52SPeter A. G. Crosthwaite 
368929d1b52SPeter A. G. Crosthwaite static void xilinx_spi_class_init(ObjectClass *klass, void *data)
369929d1b52SPeter A. G. Crosthwaite {
370929d1b52SPeter A. G. Crosthwaite     DeviceClass *dc = DEVICE_CLASS(klass);
371929d1b52SPeter A. G. Crosthwaite 
372a7e1562cSPhilippe Mathieu-Daudé     dc->realize = xilinx_spi_realize;
373929d1b52SPeter A. G. Crosthwaite     dc->reset = xlx_spi_reset;
3744f67d30bSMarc-André Lureau     device_class_set_props(dc, xilinx_spi_properties);
375929d1b52SPeter A. G. Crosthwaite     dc->vmsd = &vmstate_xilinx_spi;
376929d1b52SPeter A. G. Crosthwaite }
377929d1b52SPeter A. G. Crosthwaite 
3788c43a6f0SAndreas Färber static const TypeInfo xilinx_spi_info = {
3793efc10e1SAndreas Färber     .name           = TYPE_XILINX_SPI,
380929d1b52SPeter A. G. Crosthwaite     .parent         = TYPE_SYS_BUS_DEVICE,
381929d1b52SPeter A. G. Crosthwaite     .instance_size  = sizeof(XilinxSPI),
382929d1b52SPeter A. G. Crosthwaite     .class_init     = xilinx_spi_class_init,
383929d1b52SPeter A. G. Crosthwaite };
384929d1b52SPeter A. G. Crosthwaite 
385929d1b52SPeter A. G. Crosthwaite static void xilinx_spi_register_types(void)
386929d1b52SPeter A. G. Crosthwaite {
387929d1b52SPeter A. G. Crosthwaite     type_register_static(&xilinx_spi_info);
388929d1b52SPeter A. G. Crosthwaite }
389929d1b52SPeter A. G. Crosthwaite 
390929d1b52SPeter A. G. Crosthwaite type_init(xilinx_spi_register_types)
391