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