xref: /qemu/hw/ssi/xilinx_spi.c (revision 8ef94f0bc9167f246b41cb1188bf80dcd84b49fe)
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 
27*8ef94f0bSPeter Maydell #include "qemu/osdep.h"
2883c9f4caSPaolo Bonzini #include "hw/sysbus.h"
299c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
301de7afc9SPaolo Bonzini #include "qemu/log.h"
31fd7f0d66SPaolo Bonzini #include "qemu/fifo8.h"
32929d1b52SPeter A. G. Crosthwaite 
338fd06719SAlistair Francis #include "hw/ssi/ssi.h"
34929d1b52SPeter A. G. Crosthwaite 
35929d1b52SPeter A. G. Crosthwaite #ifdef XILINX_SPI_ERR_DEBUG
36929d1b52SPeter A. G. Crosthwaite #define DB_PRINT(...) do { \
37929d1b52SPeter A. G. Crosthwaite     fprintf(stderr,  ": %s: ", __func__); \
38929d1b52SPeter A. G. Crosthwaite     fprintf(stderr, ## __VA_ARGS__); \
39929d1b52SPeter A. G. Crosthwaite     } while (0);
40929d1b52SPeter A. G. Crosthwaite #else
41929d1b52SPeter A. G. Crosthwaite     #define DB_PRINT(...)
42929d1b52SPeter A. G. Crosthwaite #endif
43929d1b52SPeter A. G. Crosthwaite 
44929d1b52SPeter A. G. Crosthwaite #define R_DGIER     (0x1c / 4)
45929d1b52SPeter A. G. Crosthwaite #define R_DGIER_IE  (1 << 31)
46929d1b52SPeter A. G. Crosthwaite 
47929d1b52SPeter A. G. Crosthwaite #define R_IPISR     (0x20 / 4)
48929d1b52SPeter A. G. Crosthwaite #define IRQ_DRR_NOT_EMPTY    (1 << (31 - 23))
49929d1b52SPeter A. G. Crosthwaite #define IRQ_DRR_OVERRUN      (1 << (31 - 26))
50929d1b52SPeter A. G. Crosthwaite #define IRQ_DRR_FULL         (1 << (31 - 27))
51929d1b52SPeter A. G. Crosthwaite #define IRQ_TX_FF_HALF_EMPTY (1 << 6)
52929d1b52SPeter A. G. Crosthwaite #define IRQ_DTR_UNDERRUN     (1 << 3)
53929d1b52SPeter A. G. Crosthwaite #define IRQ_DTR_EMPTY        (1 << (31 - 29))
54929d1b52SPeter A. G. Crosthwaite 
55929d1b52SPeter A. G. Crosthwaite #define R_IPIER     (0x28 / 4)
56929d1b52SPeter A. G. Crosthwaite #define R_SRR       (0x40 / 4)
57929d1b52SPeter A. G. Crosthwaite #define R_SPICR     (0x60 / 4)
58929d1b52SPeter A. G. Crosthwaite #define R_SPICR_TXFF_RST     (1 << 5)
59929d1b52SPeter A. G. Crosthwaite #define R_SPICR_RXFF_RST     (1 << 6)
60929d1b52SPeter A. G. Crosthwaite #define R_SPICR_MTI          (1 << 8)
61929d1b52SPeter A. G. Crosthwaite 
62929d1b52SPeter A. G. Crosthwaite #define R_SPISR     (0x64 / 4)
63929d1b52SPeter A. G. Crosthwaite #define SR_TX_FULL    (1 << 3)
64929d1b52SPeter A. G. Crosthwaite #define SR_TX_EMPTY   (1 << 2)
65929d1b52SPeter A. G. Crosthwaite #define SR_RX_FULL    (1 << 1)
66929d1b52SPeter A. G. Crosthwaite #define SR_RX_EMPTY   (1 << 0)
67929d1b52SPeter A. G. Crosthwaite 
68929d1b52SPeter A. G. Crosthwaite #define R_SPIDTR    (0x68 / 4)
69929d1b52SPeter A. G. Crosthwaite #define R_SPIDRR    (0x6C / 4)
70929d1b52SPeter A. G. Crosthwaite #define R_SPISSR    (0x70 / 4)
71929d1b52SPeter A. G. Crosthwaite #define R_TX_FF_OCY (0x74 / 4)
72929d1b52SPeter A. G. Crosthwaite #define R_RX_FF_OCY (0x78 / 4)
73929d1b52SPeter A. G. Crosthwaite #define R_MAX       (0x7C / 4)
74929d1b52SPeter A. G. Crosthwaite 
75929d1b52SPeter A. G. Crosthwaite #define FIFO_CAPACITY 256
76929d1b52SPeter A. G. Crosthwaite 
773efc10e1SAndreas Färber #define TYPE_XILINX_SPI "xlnx.xps-spi"
783efc10e1SAndreas Färber #define XILINX_SPI(obj) OBJECT_CHECK(XilinxSPI, (obj), TYPE_XILINX_SPI)
793efc10e1SAndreas Färber 
80929d1b52SPeter A. G. Crosthwaite typedef struct XilinxSPI {
813efc10e1SAndreas Färber     SysBusDevice parent_obj;
823efc10e1SAndreas Färber 
83929d1b52SPeter A. G. Crosthwaite     MemoryRegion mmio;
84929d1b52SPeter A. G. Crosthwaite 
85929d1b52SPeter A. G. Crosthwaite     qemu_irq irq;
86929d1b52SPeter A. G. Crosthwaite     int irqline;
87929d1b52SPeter A. G. Crosthwaite 
88929d1b52SPeter A. G. Crosthwaite     uint8_t num_cs;
89929d1b52SPeter A. G. Crosthwaite     qemu_irq *cs_lines;
90929d1b52SPeter A. G. Crosthwaite 
91929d1b52SPeter A. G. Crosthwaite     SSIBus *spi;
92929d1b52SPeter A. G. Crosthwaite 
93929d1b52SPeter A. G. Crosthwaite     Fifo8 rx_fifo;
94929d1b52SPeter A. G. Crosthwaite     Fifo8 tx_fifo;
95929d1b52SPeter A. G. Crosthwaite 
96929d1b52SPeter A. G. Crosthwaite     uint32_t regs[R_MAX];
97929d1b52SPeter A. G. Crosthwaite } XilinxSPI;
98929d1b52SPeter A. G. Crosthwaite 
99929d1b52SPeter A. G. Crosthwaite static void txfifo_reset(XilinxSPI *s)
100929d1b52SPeter A. G. Crosthwaite {
101929d1b52SPeter A. G. Crosthwaite     fifo8_reset(&s->tx_fifo);
102929d1b52SPeter A. G. Crosthwaite 
103929d1b52SPeter A. G. Crosthwaite     s->regs[R_SPISR] &= ~SR_TX_FULL;
104929d1b52SPeter A. G. Crosthwaite     s->regs[R_SPISR] |= SR_TX_EMPTY;
105929d1b52SPeter A. G. Crosthwaite }
106929d1b52SPeter A. G. Crosthwaite 
107929d1b52SPeter A. G. Crosthwaite static void rxfifo_reset(XilinxSPI *s)
108929d1b52SPeter A. G. Crosthwaite {
109929d1b52SPeter A. G. Crosthwaite     fifo8_reset(&s->rx_fifo);
110929d1b52SPeter A. G. Crosthwaite 
111929d1b52SPeter A. G. Crosthwaite     s->regs[R_SPISR] |= SR_RX_EMPTY;
112929d1b52SPeter A. G. Crosthwaite     s->regs[R_SPISR] &= ~SR_RX_FULL;
113929d1b52SPeter A. G. Crosthwaite }
114929d1b52SPeter A. G. Crosthwaite 
115929d1b52SPeter A. G. Crosthwaite static void xlx_spi_update_cs(XilinxSPI *s)
116929d1b52SPeter A. G. Crosthwaite {
117929d1b52SPeter A. G. Crosthwaite     int i;
118929d1b52SPeter A. G. Crosthwaite 
119929d1b52SPeter A. G. Crosthwaite     for (i = 0; i < s->num_cs; ++i) {
120929d1b52SPeter A. G. Crosthwaite         qemu_set_irq(s->cs_lines[i], !(~s->regs[R_SPISSR] & 1 << i));
121929d1b52SPeter A. G. Crosthwaite     }
122929d1b52SPeter A. G. Crosthwaite }
123929d1b52SPeter A. G. Crosthwaite 
124929d1b52SPeter A. G. Crosthwaite static void xlx_spi_update_irq(XilinxSPI *s)
125929d1b52SPeter A. G. Crosthwaite {
126929d1b52SPeter A. G. Crosthwaite     uint32_t pending;
127929d1b52SPeter A. G. Crosthwaite 
128929d1b52SPeter A. G. Crosthwaite     s->regs[R_IPISR] |=
129929d1b52SPeter A. G. Crosthwaite             (!fifo8_is_empty(&s->rx_fifo) ? IRQ_DRR_NOT_EMPTY : 0) |
130929d1b52SPeter A. G. Crosthwaite             (fifo8_is_full(&s->rx_fifo) ? IRQ_DRR_FULL : 0);
131929d1b52SPeter A. G. Crosthwaite 
132929d1b52SPeter A. G. Crosthwaite     pending = s->regs[R_IPISR] & s->regs[R_IPIER];
133929d1b52SPeter A. G. Crosthwaite 
134929d1b52SPeter A. G. Crosthwaite     pending = pending && (s->regs[R_DGIER] & R_DGIER_IE);
135929d1b52SPeter A. G. Crosthwaite     pending = !!pending;
136929d1b52SPeter A. G. Crosthwaite 
137929d1b52SPeter A. G. Crosthwaite     /* This call lies right in the data paths so don't call the
138929d1b52SPeter A. G. Crosthwaite        irq chain unless things really changed.  */
139929d1b52SPeter A. G. Crosthwaite     if (pending != s->irqline) {
140929d1b52SPeter A. G. Crosthwaite         s->irqline = pending;
141929d1b52SPeter A. G. Crosthwaite         DB_PRINT("irq_change of state %d ISR:%x IER:%X\n",
142929d1b52SPeter A. G. Crosthwaite                     pending, s->regs[R_IPISR], s->regs[R_IPIER]);
143929d1b52SPeter A. G. Crosthwaite         qemu_set_irq(s->irq, pending);
144929d1b52SPeter A. G. Crosthwaite     }
145929d1b52SPeter A. G. Crosthwaite 
146929d1b52SPeter A. G. Crosthwaite }
147929d1b52SPeter A. G. Crosthwaite 
148929d1b52SPeter A. G. Crosthwaite static void xlx_spi_do_reset(XilinxSPI *s)
149929d1b52SPeter A. G. Crosthwaite {
150929d1b52SPeter A. G. Crosthwaite     memset(s->regs, 0, sizeof s->regs);
151929d1b52SPeter A. G. Crosthwaite 
152929d1b52SPeter A. G. Crosthwaite     rxfifo_reset(s);
153929d1b52SPeter A. G. Crosthwaite     txfifo_reset(s);
154929d1b52SPeter A. G. Crosthwaite 
155929d1b52SPeter A. G. Crosthwaite     s->regs[R_SPISSR] = ~0;
156929d1b52SPeter A. G. Crosthwaite     xlx_spi_update_irq(s);
157929d1b52SPeter A. G. Crosthwaite     xlx_spi_update_cs(s);
158929d1b52SPeter A. G. Crosthwaite }
159929d1b52SPeter A. G. Crosthwaite 
160929d1b52SPeter A. G. Crosthwaite static void xlx_spi_reset(DeviceState *d)
161929d1b52SPeter A. G. Crosthwaite {
1623efc10e1SAndreas Färber     xlx_spi_do_reset(XILINX_SPI(d));
163929d1b52SPeter A. G. Crosthwaite }
164929d1b52SPeter A. G. Crosthwaite 
165929d1b52SPeter A. G. Crosthwaite static inline int spi_master_enabled(XilinxSPI *s)
166929d1b52SPeter A. G. Crosthwaite {
167929d1b52SPeter A. G. Crosthwaite     return !(s->regs[R_SPICR] & R_SPICR_MTI);
168929d1b52SPeter A. G. Crosthwaite }
169929d1b52SPeter A. G. Crosthwaite 
170929d1b52SPeter A. G. Crosthwaite static void spi_flush_txfifo(XilinxSPI *s)
171929d1b52SPeter A. G. Crosthwaite {
172929d1b52SPeter A. G. Crosthwaite     uint32_t tx;
173929d1b52SPeter A. G. Crosthwaite     uint32_t rx;
174929d1b52SPeter A. G. Crosthwaite 
175929d1b52SPeter A. G. Crosthwaite     while (!fifo8_is_empty(&s->tx_fifo)) {
176929d1b52SPeter A. G. Crosthwaite         tx = (uint32_t)fifo8_pop(&s->tx_fifo);
177929d1b52SPeter A. G. Crosthwaite         DB_PRINT("data tx:%x\n", tx);
178929d1b52SPeter A. G. Crosthwaite         rx = ssi_transfer(s->spi, tx);
179929d1b52SPeter A. G. Crosthwaite         DB_PRINT("data rx:%x\n", rx);
180929d1b52SPeter A. G. Crosthwaite         if (fifo8_is_full(&s->rx_fifo)) {
181929d1b52SPeter A. G. Crosthwaite             s->regs[R_IPISR] |= IRQ_DRR_OVERRUN;
182929d1b52SPeter A. G. Crosthwaite         } else {
183929d1b52SPeter A. G. Crosthwaite             fifo8_push(&s->rx_fifo, (uint8_t)rx);
184929d1b52SPeter A. G. Crosthwaite             if (fifo8_is_full(&s->rx_fifo)) {
185929d1b52SPeter A. G. Crosthwaite                 s->regs[R_SPISR] |= SR_RX_FULL;
186929d1b52SPeter A. G. Crosthwaite                 s->regs[R_IPISR] |= IRQ_DRR_FULL;
187929d1b52SPeter A. G. Crosthwaite             }
188929d1b52SPeter A. G. Crosthwaite         }
189929d1b52SPeter A. G. Crosthwaite 
190929d1b52SPeter A. G. Crosthwaite         s->regs[R_SPISR] &= ~SR_RX_EMPTY;
191929d1b52SPeter A. G. Crosthwaite         s->regs[R_SPISR] &= ~SR_TX_FULL;
192929d1b52SPeter A. G. Crosthwaite         s->regs[R_SPISR] |= SR_TX_EMPTY;
193929d1b52SPeter A. G. Crosthwaite 
194929d1b52SPeter A. G. Crosthwaite         s->regs[R_IPISR] |= IRQ_DTR_EMPTY;
195929d1b52SPeter A. G. Crosthwaite         s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY;
196929d1b52SPeter A. G. Crosthwaite     }
197929d1b52SPeter A. G. Crosthwaite 
198929d1b52SPeter A. G. Crosthwaite }
199929d1b52SPeter A. G. Crosthwaite 
200929d1b52SPeter A. G. Crosthwaite static uint64_t
201a8170e5eSAvi Kivity spi_read(void *opaque, hwaddr addr, unsigned int size)
202929d1b52SPeter A. G. Crosthwaite {
203929d1b52SPeter A. G. Crosthwaite     XilinxSPI *s = opaque;
204929d1b52SPeter A. G. Crosthwaite     uint32_t r = 0;
205929d1b52SPeter A. G. Crosthwaite 
206929d1b52SPeter A. G. Crosthwaite     addr >>= 2;
207929d1b52SPeter A. G. Crosthwaite     switch (addr) {
208929d1b52SPeter A. G. Crosthwaite     case R_SPIDRR:
209929d1b52SPeter A. G. Crosthwaite         if (fifo8_is_empty(&s->rx_fifo)) {
210929d1b52SPeter A. G. Crosthwaite             DB_PRINT("Read from empty FIFO!\n");
211929d1b52SPeter A. G. Crosthwaite             return 0xdeadbeef;
212929d1b52SPeter A. G. Crosthwaite         }
213929d1b52SPeter A. G. Crosthwaite 
214929d1b52SPeter A. G. Crosthwaite         s->regs[R_SPISR] &= ~SR_RX_FULL;
215929d1b52SPeter A. G. Crosthwaite         r = fifo8_pop(&s->rx_fifo);
216929d1b52SPeter A. G. Crosthwaite         if (fifo8_is_empty(&s->rx_fifo)) {
217929d1b52SPeter A. G. Crosthwaite             s->regs[R_SPISR] |= SR_RX_EMPTY;
218929d1b52SPeter A. G. Crosthwaite         }
219929d1b52SPeter A. G. Crosthwaite         break;
220929d1b52SPeter A. G. Crosthwaite 
221929d1b52SPeter A. G. Crosthwaite     case R_SPISR:
222929d1b52SPeter A. G. Crosthwaite         r = s->regs[addr];
223929d1b52SPeter A. G. Crosthwaite         break;
224929d1b52SPeter A. G. Crosthwaite 
225929d1b52SPeter A. G. Crosthwaite     default:
226929d1b52SPeter A. G. Crosthwaite         if (addr < ARRAY_SIZE(s->regs)) {
227929d1b52SPeter A. G. Crosthwaite             r = s->regs[addr];
228929d1b52SPeter A. G. Crosthwaite         }
229929d1b52SPeter A. G. Crosthwaite         break;
230929d1b52SPeter A. G. Crosthwaite 
231929d1b52SPeter A. G. Crosthwaite     }
232929d1b52SPeter A. G. Crosthwaite     DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, r);
233929d1b52SPeter A. G. Crosthwaite     xlx_spi_update_irq(s);
234929d1b52SPeter A. G. Crosthwaite     return r;
235929d1b52SPeter A. G. Crosthwaite }
236929d1b52SPeter A. G. Crosthwaite 
237929d1b52SPeter A. G. Crosthwaite static void
238a8170e5eSAvi Kivity spi_write(void *opaque, hwaddr addr,
239929d1b52SPeter A. G. Crosthwaite             uint64_t val64, unsigned int size)
240929d1b52SPeter A. G. Crosthwaite {
241929d1b52SPeter A. G. Crosthwaite     XilinxSPI *s = opaque;
242929d1b52SPeter A. G. Crosthwaite     uint32_t value = val64;
243929d1b52SPeter A. G. Crosthwaite 
244929d1b52SPeter A. G. Crosthwaite     DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, value);
245929d1b52SPeter A. G. Crosthwaite     addr >>= 2;
246929d1b52SPeter A. G. Crosthwaite     switch (addr) {
247929d1b52SPeter A. G. Crosthwaite     case R_SRR:
248929d1b52SPeter A. G. Crosthwaite         if (value != 0xa) {
249929d1b52SPeter A. G. Crosthwaite             DB_PRINT("Invalid write to SRR %x\n", value);
250929d1b52SPeter A. G. Crosthwaite         } else {
251929d1b52SPeter A. G. Crosthwaite             xlx_spi_do_reset(s);
252929d1b52SPeter A. G. Crosthwaite         }
253929d1b52SPeter A. G. Crosthwaite         break;
254929d1b52SPeter A. G. Crosthwaite 
255929d1b52SPeter A. G. Crosthwaite     case R_SPIDTR:
256929d1b52SPeter A. G. Crosthwaite         s->regs[R_SPISR] &= ~SR_TX_EMPTY;
257929d1b52SPeter A. G. Crosthwaite         fifo8_push(&s->tx_fifo, (uint8_t)value);
258929d1b52SPeter A. G. Crosthwaite         if (fifo8_is_full(&s->tx_fifo)) {
259929d1b52SPeter A. G. Crosthwaite             s->regs[R_SPISR] |= SR_TX_FULL;
260929d1b52SPeter A. G. Crosthwaite         }
261929d1b52SPeter A. G. Crosthwaite         if (!spi_master_enabled(s)) {
262929d1b52SPeter A. G. Crosthwaite             goto done;
263929d1b52SPeter A. G. Crosthwaite         } else {
264929d1b52SPeter A. G. Crosthwaite             DB_PRINT("DTR and master enabled\n");
265929d1b52SPeter A. G. Crosthwaite         }
266929d1b52SPeter A. G. Crosthwaite         spi_flush_txfifo(s);
267929d1b52SPeter A. G. Crosthwaite         break;
268929d1b52SPeter A. G. Crosthwaite 
269929d1b52SPeter A. G. Crosthwaite     case R_SPISR:
270929d1b52SPeter A. G. Crosthwaite         DB_PRINT("Invalid write to SPISR %x\n", value);
271929d1b52SPeter A. G. Crosthwaite         break;
272929d1b52SPeter A. G. Crosthwaite 
273929d1b52SPeter A. G. Crosthwaite     case R_IPISR:
274929d1b52SPeter A. G. Crosthwaite         /* Toggle the bits.  */
275929d1b52SPeter A. G. Crosthwaite         s->regs[addr] ^= value;
276929d1b52SPeter A. G. Crosthwaite         break;
277929d1b52SPeter A. G. Crosthwaite 
278929d1b52SPeter A. G. Crosthwaite     /* Slave Select Register.  */
279929d1b52SPeter A. G. Crosthwaite     case R_SPISSR:
280929d1b52SPeter A. G. Crosthwaite         s->regs[addr] = value;
281929d1b52SPeter A. G. Crosthwaite         xlx_spi_update_cs(s);
282929d1b52SPeter A. G. Crosthwaite         break;
283929d1b52SPeter A. G. Crosthwaite 
284929d1b52SPeter A. G. Crosthwaite     case R_SPICR:
285929d1b52SPeter A. G. Crosthwaite         /* FIXME: reset irq and sr state to empty queues.  */
286929d1b52SPeter A. G. Crosthwaite         if (value & R_SPICR_RXFF_RST) {
287929d1b52SPeter A. G. Crosthwaite             rxfifo_reset(s);
288929d1b52SPeter A. G. Crosthwaite         }
289929d1b52SPeter A. G. Crosthwaite 
290929d1b52SPeter A. G. Crosthwaite         if (value & R_SPICR_TXFF_RST) {
291929d1b52SPeter A. G. Crosthwaite             txfifo_reset(s);
292929d1b52SPeter A. G. Crosthwaite         }
293929d1b52SPeter A. G. Crosthwaite         value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST);
294929d1b52SPeter A. G. Crosthwaite         s->regs[addr] = value;
295929d1b52SPeter A. G. Crosthwaite 
296929d1b52SPeter A. G. Crosthwaite         if (!(value & R_SPICR_MTI)) {
297929d1b52SPeter A. G. Crosthwaite             spi_flush_txfifo(s);
298929d1b52SPeter A. G. Crosthwaite         }
299929d1b52SPeter A. G. Crosthwaite         break;
300929d1b52SPeter A. G. Crosthwaite 
301929d1b52SPeter A. G. Crosthwaite     default:
302929d1b52SPeter A. G. Crosthwaite         if (addr < ARRAY_SIZE(s->regs)) {
303929d1b52SPeter A. G. Crosthwaite             s->regs[addr] = value;
304929d1b52SPeter A. G. Crosthwaite         }
305929d1b52SPeter A. G. Crosthwaite         break;
306929d1b52SPeter A. G. Crosthwaite     }
307929d1b52SPeter A. G. Crosthwaite 
308929d1b52SPeter A. G. Crosthwaite done:
309929d1b52SPeter A. G. Crosthwaite     xlx_spi_update_irq(s);
310929d1b52SPeter A. G. Crosthwaite }
311929d1b52SPeter A. G. Crosthwaite 
312929d1b52SPeter A. G. Crosthwaite static const MemoryRegionOps spi_ops = {
313929d1b52SPeter A. G. Crosthwaite     .read = spi_read,
314929d1b52SPeter A. G. Crosthwaite     .write = spi_write,
315929d1b52SPeter A. G. Crosthwaite     .endianness = DEVICE_NATIVE_ENDIAN,
316929d1b52SPeter A. G. Crosthwaite     .valid = {
317929d1b52SPeter A. G. Crosthwaite         .min_access_size = 4,
318929d1b52SPeter A. G. Crosthwaite         .max_access_size = 4
319929d1b52SPeter A. G. Crosthwaite     }
320929d1b52SPeter A. G. Crosthwaite };
321929d1b52SPeter A. G. Crosthwaite 
3223efc10e1SAndreas Färber static int xilinx_spi_init(SysBusDevice *sbd)
323929d1b52SPeter A. G. Crosthwaite {
3243efc10e1SAndreas Färber     DeviceState *dev = DEVICE(sbd);
3253efc10e1SAndreas Färber     XilinxSPI *s = XILINX_SPI(dev);
326929d1b52SPeter A. G. Crosthwaite     int i;
327929d1b52SPeter A. G. Crosthwaite 
328929d1b52SPeter A. G. Crosthwaite     DB_PRINT("\n");
329b4ae3cfaSPeter Crosthwaite 
3303efc10e1SAndreas Färber     s->spi = ssi_create_bus(dev, "spi");
331b4ae3cfaSPeter Crosthwaite 
3323efc10e1SAndreas Färber     sysbus_init_irq(sbd, &s->irq);
333c75f3c04SPeter Crosthwaite     s->cs_lines = g_new0(qemu_irq, s->num_cs);
3343efc10e1SAndreas Färber     ssi_auto_connect_slaves(dev, s->cs_lines, s->spi);
335929d1b52SPeter A. G. Crosthwaite     for (i = 0; i < s->num_cs; ++i) {
3363efc10e1SAndreas Färber         sysbus_init_irq(sbd, &s->cs_lines[i]);
337929d1b52SPeter A. G. Crosthwaite     }
338929d1b52SPeter A. G. Crosthwaite 
33929776739SPaolo Bonzini     memory_region_init_io(&s->mmio, OBJECT(s), &spi_ops, s,
34029776739SPaolo Bonzini                           "xilinx-spi", R_MAX * 4);
3413efc10e1SAndreas Färber     sysbus_init_mmio(sbd, &s->mmio);
342929d1b52SPeter A. G. Crosthwaite 
343929d1b52SPeter A. G. Crosthwaite     s->irqline = -1;
344929d1b52SPeter A. G. Crosthwaite 
345929d1b52SPeter A. G. Crosthwaite     fifo8_create(&s->tx_fifo, FIFO_CAPACITY);
346929d1b52SPeter A. G. Crosthwaite     fifo8_create(&s->rx_fifo, FIFO_CAPACITY);
347929d1b52SPeter A. G. Crosthwaite 
348929d1b52SPeter A. G. Crosthwaite     return 0;
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     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
372929d1b52SPeter A. G. Crosthwaite 
373929d1b52SPeter A. G. Crosthwaite     k->init = xilinx_spi_init;
374929d1b52SPeter A. G. Crosthwaite     dc->reset = xlx_spi_reset;
375929d1b52SPeter A. G. Crosthwaite     dc->props = xilinx_spi_properties;
376929d1b52SPeter A. G. Crosthwaite     dc->vmsd = &vmstate_xilinx_spi;
377929d1b52SPeter A. G. Crosthwaite }
378929d1b52SPeter A. G. Crosthwaite 
3798c43a6f0SAndreas Färber static const TypeInfo xilinx_spi_info = {
3803efc10e1SAndreas Färber     .name           = TYPE_XILINX_SPI,
381929d1b52SPeter A. G. Crosthwaite     .parent         = TYPE_SYS_BUS_DEVICE,
382929d1b52SPeter A. G. Crosthwaite     .instance_size  = sizeof(XilinxSPI),
383929d1b52SPeter A. G. Crosthwaite     .class_init     = xilinx_spi_class_init,
384929d1b52SPeter A. G. Crosthwaite };
385929d1b52SPeter A. G. Crosthwaite 
386929d1b52SPeter A. G. Crosthwaite static void xilinx_spi_register_types(void)
387929d1b52SPeter A. G. Crosthwaite {
388929d1b52SPeter A. G. Crosthwaite     type_register_static(&xilinx_spi_info);
389929d1b52SPeter A. G. Crosthwaite }
390929d1b52SPeter A. G. Crosthwaite 
391929d1b52SPeter A. G. Crosthwaite type_init(xilinx_spi_register_types)
392