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; 159*a0eaa126SChris Rauer s->regs[R_SPICR] = R_SPICR_MTI; 160929d1b52SPeter A. G. Crosthwaite xlx_spi_update_irq(s); 161929d1b52SPeter A. G. Crosthwaite xlx_spi_update_cs(s); 162929d1b52SPeter A. G. Crosthwaite } 163929d1b52SPeter A. G. Crosthwaite 164929d1b52SPeter A. G. Crosthwaite static void xlx_spi_reset(DeviceState *d) 165929d1b52SPeter A. G. Crosthwaite { 1663efc10e1SAndreas Färber xlx_spi_do_reset(XILINX_SPI(d)); 167929d1b52SPeter A. G. Crosthwaite } 168929d1b52SPeter A. G. Crosthwaite 169929d1b52SPeter A. G. Crosthwaite static inline int spi_master_enabled(XilinxSPI *s) 170929d1b52SPeter A. G. Crosthwaite { 171929d1b52SPeter A. G. Crosthwaite return !(s->regs[R_SPICR] & R_SPICR_MTI); 172929d1b52SPeter A. G. Crosthwaite } 173929d1b52SPeter A. G. Crosthwaite 174929d1b52SPeter A. G. Crosthwaite static void spi_flush_txfifo(XilinxSPI *s) 175929d1b52SPeter A. G. Crosthwaite { 176929d1b52SPeter A. G. Crosthwaite uint32_t tx; 177929d1b52SPeter A. G. Crosthwaite uint32_t rx; 178929d1b52SPeter A. G. Crosthwaite 179929d1b52SPeter A. G. Crosthwaite while (!fifo8_is_empty(&s->tx_fifo)) { 180929d1b52SPeter A. G. Crosthwaite tx = (uint32_t)fifo8_pop(&s->tx_fifo); 181929d1b52SPeter A. G. Crosthwaite DB_PRINT("data tx:%x\n", tx); 182929d1b52SPeter A. G. Crosthwaite rx = ssi_transfer(s->spi, tx); 183929d1b52SPeter A. G. Crosthwaite DB_PRINT("data rx:%x\n", rx); 184929d1b52SPeter A. G. Crosthwaite if (fifo8_is_full(&s->rx_fifo)) { 185929d1b52SPeter A. G. Crosthwaite s->regs[R_IPISR] |= IRQ_DRR_OVERRUN; 186929d1b52SPeter A. G. Crosthwaite } else { 187929d1b52SPeter A. G. Crosthwaite fifo8_push(&s->rx_fifo, (uint8_t)rx); 188929d1b52SPeter A. G. Crosthwaite if (fifo8_is_full(&s->rx_fifo)) { 189929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] |= SR_RX_FULL; 190929d1b52SPeter A. G. Crosthwaite s->regs[R_IPISR] |= IRQ_DRR_FULL; 191929d1b52SPeter A. G. Crosthwaite } 192929d1b52SPeter A. G. Crosthwaite } 193929d1b52SPeter A. G. Crosthwaite 194929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] &= ~SR_RX_EMPTY; 195929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] &= ~SR_TX_FULL; 196929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] |= SR_TX_EMPTY; 197929d1b52SPeter A. G. Crosthwaite 198929d1b52SPeter A. G. Crosthwaite s->regs[R_IPISR] |= IRQ_DTR_EMPTY; 199929d1b52SPeter A. G. Crosthwaite s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY; 200929d1b52SPeter A. G. Crosthwaite } 201929d1b52SPeter A. G. Crosthwaite 202929d1b52SPeter A. G. Crosthwaite } 203929d1b52SPeter A. G. Crosthwaite 204929d1b52SPeter A. G. Crosthwaite static uint64_t 205a8170e5eSAvi Kivity spi_read(void *opaque, hwaddr addr, unsigned int size) 206929d1b52SPeter A. G. Crosthwaite { 207929d1b52SPeter A. G. Crosthwaite XilinxSPI *s = opaque; 208929d1b52SPeter A. G. Crosthwaite uint32_t r = 0; 209929d1b52SPeter A. G. Crosthwaite 210929d1b52SPeter A. G. Crosthwaite addr >>= 2; 211929d1b52SPeter A. G. Crosthwaite switch (addr) { 212929d1b52SPeter A. G. Crosthwaite case R_SPIDRR: 213929d1b52SPeter A. G. Crosthwaite if (fifo8_is_empty(&s->rx_fifo)) { 214929d1b52SPeter A. G. Crosthwaite DB_PRINT("Read from empty FIFO!\n"); 215929d1b52SPeter A. G. Crosthwaite return 0xdeadbeef; 216929d1b52SPeter A. G. Crosthwaite } 217929d1b52SPeter A. G. Crosthwaite 218929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] &= ~SR_RX_FULL; 219929d1b52SPeter A. G. Crosthwaite r = fifo8_pop(&s->rx_fifo); 220929d1b52SPeter A. G. Crosthwaite if (fifo8_is_empty(&s->rx_fifo)) { 221929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] |= SR_RX_EMPTY; 222929d1b52SPeter A. G. Crosthwaite } 223929d1b52SPeter A. G. Crosthwaite break; 224929d1b52SPeter A. G. Crosthwaite 225929d1b52SPeter A. G. Crosthwaite case R_SPISR: 226929d1b52SPeter A. G. Crosthwaite r = s->regs[addr]; 227929d1b52SPeter A. G. Crosthwaite break; 228929d1b52SPeter A. G. Crosthwaite 229929d1b52SPeter A. G. Crosthwaite default: 230929d1b52SPeter A. G. Crosthwaite if (addr < ARRAY_SIZE(s->regs)) { 231929d1b52SPeter A. G. Crosthwaite r = s->regs[addr]; 232929d1b52SPeter A. G. Crosthwaite } 233929d1b52SPeter A. G. Crosthwaite break; 234929d1b52SPeter A. G. Crosthwaite 235929d1b52SPeter A. G. Crosthwaite } 236883f2c59SPhilippe Mathieu-Daudé DB_PRINT("addr=" HWADDR_FMT_plx " = %x\n", addr * 4, r); 237929d1b52SPeter A. G. Crosthwaite xlx_spi_update_irq(s); 238929d1b52SPeter A. G. Crosthwaite return r; 239929d1b52SPeter A. G. Crosthwaite } 240929d1b52SPeter A. G. Crosthwaite 241929d1b52SPeter A. G. Crosthwaite static void 242a8170e5eSAvi Kivity spi_write(void *opaque, hwaddr addr, 243929d1b52SPeter A. G. Crosthwaite uint64_t val64, unsigned int size) 244929d1b52SPeter A. G. Crosthwaite { 245929d1b52SPeter A. G. Crosthwaite XilinxSPI *s = opaque; 246929d1b52SPeter A. G. Crosthwaite uint32_t value = val64; 247929d1b52SPeter A. G. Crosthwaite 248883f2c59SPhilippe Mathieu-Daudé DB_PRINT("addr=" HWADDR_FMT_plx " = %x\n", addr, value); 249929d1b52SPeter A. G. Crosthwaite addr >>= 2; 250929d1b52SPeter A. G. Crosthwaite switch (addr) { 251929d1b52SPeter A. G. Crosthwaite case R_SRR: 252929d1b52SPeter A. G. Crosthwaite if (value != 0xa) { 253929d1b52SPeter A. G. Crosthwaite DB_PRINT("Invalid write to SRR %x\n", value); 254929d1b52SPeter A. G. Crosthwaite } else { 255929d1b52SPeter A. G. Crosthwaite xlx_spi_do_reset(s); 256929d1b52SPeter A. G. Crosthwaite } 257929d1b52SPeter A. G. Crosthwaite break; 258929d1b52SPeter A. G. Crosthwaite 259929d1b52SPeter A. G. Crosthwaite case R_SPIDTR: 260929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] &= ~SR_TX_EMPTY; 261929d1b52SPeter A. G. Crosthwaite fifo8_push(&s->tx_fifo, (uint8_t)value); 262929d1b52SPeter A. G. Crosthwaite if (fifo8_is_full(&s->tx_fifo)) { 263929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] |= SR_TX_FULL; 264929d1b52SPeter A. G. Crosthwaite } 265929d1b52SPeter A. G. Crosthwaite if (!spi_master_enabled(s)) { 266929d1b52SPeter A. G. Crosthwaite goto done; 267929d1b52SPeter A. G. Crosthwaite } else { 268929d1b52SPeter A. G. Crosthwaite DB_PRINT("DTR and master enabled\n"); 269929d1b52SPeter A. G. Crosthwaite } 270929d1b52SPeter A. G. Crosthwaite spi_flush_txfifo(s); 271929d1b52SPeter A. G. Crosthwaite break; 272929d1b52SPeter A. G. Crosthwaite 273929d1b52SPeter A. G. Crosthwaite case R_SPISR: 274929d1b52SPeter A. G. Crosthwaite DB_PRINT("Invalid write to SPISR %x\n", value); 275929d1b52SPeter A. G. Crosthwaite break; 276929d1b52SPeter A. G. Crosthwaite 277929d1b52SPeter A. G. Crosthwaite case R_IPISR: 278929d1b52SPeter A. G. Crosthwaite /* Toggle the bits. */ 279929d1b52SPeter A. G. Crosthwaite s->regs[addr] ^= value; 280929d1b52SPeter A. G. Crosthwaite break; 281929d1b52SPeter A. G. Crosthwaite 282929d1b52SPeter A. G. Crosthwaite /* Slave Select Register. */ 283929d1b52SPeter A. G. Crosthwaite case R_SPISSR: 284929d1b52SPeter A. G. Crosthwaite s->regs[addr] = value; 285929d1b52SPeter A. G. Crosthwaite xlx_spi_update_cs(s); 286929d1b52SPeter A. G. Crosthwaite break; 287929d1b52SPeter A. G. Crosthwaite 288929d1b52SPeter A. G. Crosthwaite case R_SPICR: 289929d1b52SPeter A. G. Crosthwaite /* FIXME: reset irq and sr state to empty queues. */ 290929d1b52SPeter A. G. Crosthwaite if (value & R_SPICR_RXFF_RST) { 291929d1b52SPeter A. G. Crosthwaite rxfifo_reset(s); 292929d1b52SPeter A. G. Crosthwaite } 293929d1b52SPeter A. G. Crosthwaite 294929d1b52SPeter A. G. Crosthwaite if (value & R_SPICR_TXFF_RST) { 295929d1b52SPeter A. G. Crosthwaite txfifo_reset(s); 296929d1b52SPeter A. G. Crosthwaite } 297929d1b52SPeter A. G. Crosthwaite value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST); 298929d1b52SPeter A. G. Crosthwaite s->regs[addr] = value; 299929d1b52SPeter A. G. Crosthwaite 300929d1b52SPeter A. G. Crosthwaite if (!(value & R_SPICR_MTI)) { 301929d1b52SPeter A. G. Crosthwaite spi_flush_txfifo(s); 302929d1b52SPeter A. G. Crosthwaite } 303929d1b52SPeter A. G. Crosthwaite break; 304929d1b52SPeter A. G. Crosthwaite 305929d1b52SPeter A. G. Crosthwaite default: 306929d1b52SPeter A. G. Crosthwaite if (addr < ARRAY_SIZE(s->regs)) { 307929d1b52SPeter A. G. Crosthwaite s->regs[addr] = value; 308929d1b52SPeter A. G. Crosthwaite } 309929d1b52SPeter A. G. Crosthwaite break; 310929d1b52SPeter A. G. Crosthwaite } 311929d1b52SPeter A. G. Crosthwaite 312929d1b52SPeter A. G. Crosthwaite done: 313929d1b52SPeter A. G. Crosthwaite xlx_spi_update_irq(s); 314929d1b52SPeter A. G. Crosthwaite } 315929d1b52SPeter A. G. Crosthwaite 316929d1b52SPeter A. G. Crosthwaite static const MemoryRegionOps spi_ops = { 317929d1b52SPeter A. G. Crosthwaite .read = spi_read, 318929d1b52SPeter A. G. Crosthwaite .write = spi_write, 319929d1b52SPeter A. G. Crosthwaite .endianness = DEVICE_NATIVE_ENDIAN, 320929d1b52SPeter A. G. Crosthwaite .valid = { 321929d1b52SPeter A. G. Crosthwaite .min_access_size = 4, 322929d1b52SPeter A. G. Crosthwaite .max_access_size = 4 323929d1b52SPeter A. G. Crosthwaite } 324929d1b52SPeter A. G. Crosthwaite }; 325929d1b52SPeter A. G. Crosthwaite 326a7e1562cSPhilippe Mathieu-Daudé static void xilinx_spi_realize(DeviceState *dev, Error **errp) 327929d1b52SPeter A. G. Crosthwaite { 328a7e1562cSPhilippe Mathieu-Daudé SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 3293efc10e1SAndreas Färber XilinxSPI *s = XILINX_SPI(dev); 330929d1b52SPeter A. G. Crosthwaite int i; 331929d1b52SPeter A. G. Crosthwaite 332929d1b52SPeter A. G. Crosthwaite DB_PRINT("\n"); 333b4ae3cfaSPeter Crosthwaite 3343efc10e1SAndreas Färber s->spi = ssi_create_bus(dev, "spi"); 335b4ae3cfaSPeter Crosthwaite 3363efc10e1SAndreas Färber sysbus_init_irq(sbd, &s->irq); 337c75f3c04SPeter Crosthwaite s->cs_lines = g_new0(qemu_irq, s->num_cs); 338929d1b52SPeter A. G. Crosthwaite for (i = 0; i < s->num_cs; ++i) { 3393efc10e1SAndreas Färber sysbus_init_irq(sbd, &s->cs_lines[i]); 340929d1b52SPeter A. G. Crosthwaite } 341929d1b52SPeter A. G. Crosthwaite 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); 345929d1b52SPeter A. G. Crosthwaite 346929d1b52SPeter A. G. Crosthwaite s->irqline = -1; 347929d1b52SPeter A. G. Crosthwaite 348929d1b52SPeter A. G. Crosthwaite fifo8_create(&s->tx_fifo, FIFO_CAPACITY); 349929d1b52SPeter A. G. Crosthwaite fifo8_create(&s->rx_fifo, FIFO_CAPACITY); 350929d1b52SPeter A. G. Crosthwaite } 351929d1b52SPeter A. G. Crosthwaite 352929d1b52SPeter A. G. Crosthwaite static const VMStateDescription vmstate_xilinx_spi = { 353929d1b52SPeter A. G. Crosthwaite .name = "xilinx_spi", 354929d1b52SPeter A. G. Crosthwaite .version_id = 1, 355929d1b52SPeter A. G. Crosthwaite .minimum_version_id = 1, 356929d1b52SPeter A. G. Crosthwaite .fields = (VMStateField[]) { 357929d1b52SPeter A. G. Crosthwaite VMSTATE_FIFO8(tx_fifo, XilinxSPI), 358929d1b52SPeter A. G. Crosthwaite VMSTATE_FIFO8(rx_fifo, XilinxSPI), 359929d1b52SPeter A. G. Crosthwaite VMSTATE_UINT32_ARRAY(regs, XilinxSPI, R_MAX), 360929d1b52SPeter A. G. Crosthwaite VMSTATE_END_OF_LIST() 361929d1b52SPeter A. G. Crosthwaite } 362929d1b52SPeter A. G. Crosthwaite }; 363929d1b52SPeter A. G. Crosthwaite 364929d1b52SPeter A. G. Crosthwaite static Property xilinx_spi_properties[] = { 365929d1b52SPeter A. G. Crosthwaite DEFINE_PROP_UINT8("num-ss-bits", XilinxSPI, num_cs, 1), 366929d1b52SPeter A. G. Crosthwaite DEFINE_PROP_END_OF_LIST(), 367929d1b52SPeter A. G. Crosthwaite }; 368929d1b52SPeter A. G. Crosthwaite 369929d1b52SPeter A. G. Crosthwaite static void xilinx_spi_class_init(ObjectClass *klass, void *data) 370929d1b52SPeter A. G. Crosthwaite { 371929d1b52SPeter A. G. Crosthwaite DeviceClass *dc = DEVICE_CLASS(klass); 372929d1b52SPeter A. G. Crosthwaite 373a7e1562cSPhilippe Mathieu-Daudé dc->realize = xilinx_spi_realize; 374929d1b52SPeter A. G. Crosthwaite dc->reset = xlx_spi_reset; 3754f67d30bSMarc-André Lureau device_class_set_props(dc, 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