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" 299c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 301de7afc9SPaolo Bonzini #include "qemu/log.h" 310b8fa32fSMarkus Armbruster #include "qemu/module.h" 32fd7f0d66SPaolo Bonzini #include "qemu/fifo8.h" 33929d1b52SPeter A. G. Crosthwaite 34*64552b6bSMarkus Armbruster #include "hw/irq.h" 358fd06719SAlistair Francis #include "hw/ssi/ssi.h" 36929d1b52SPeter A. G. Crosthwaite 37929d1b52SPeter A. G. Crosthwaite #ifdef XILINX_SPI_ERR_DEBUG 38929d1b52SPeter A. G. Crosthwaite #define DB_PRINT(...) do { \ 39929d1b52SPeter A. G. Crosthwaite fprintf(stderr, ": %s: ", __func__); \ 40929d1b52SPeter A. G. Crosthwaite fprintf(stderr, ## __VA_ARGS__); \ 412562755eSEric Blake } while (0) 42929d1b52SPeter A. G. Crosthwaite #else 43929d1b52SPeter A. G. Crosthwaite #define DB_PRINT(...) 44929d1b52SPeter A. G. Crosthwaite #endif 45929d1b52SPeter A. G. Crosthwaite 46929d1b52SPeter A. G. Crosthwaite #define R_DGIER (0x1c / 4) 47929d1b52SPeter A. G. Crosthwaite #define R_DGIER_IE (1 << 31) 48929d1b52SPeter A. G. Crosthwaite 49929d1b52SPeter A. G. Crosthwaite #define R_IPISR (0x20 / 4) 50929d1b52SPeter A. G. Crosthwaite #define IRQ_DRR_NOT_EMPTY (1 << (31 - 23)) 51929d1b52SPeter A. G. Crosthwaite #define IRQ_DRR_OVERRUN (1 << (31 - 26)) 52929d1b52SPeter A. G. Crosthwaite #define IRQ_DRR_FULL (1 << (31 - 27)) 53929d1b52SPeter A. G. Crosthwaite #define IRQ_TX_FF_HALF_EMPTY (1 << 6) 54929d1b52SPeter A. G. Crosthwaite #define IRQ_DTR_UNDERRUN (1 << 3) 55929d1b52SPeter A. G. Crosthwaite #define IRQ_DTR_EMPTY (1 << (31 - 29)) 56929d1b52SPeter A. G. Crosthwaite 57929d1b52SPeter A. G. Crosthwaite #define R_IPIER (0x28 / 4) 58929d1b52SPeter A. G. Crosthwaite #define R_SRR (0x40 / 4) 59929d1b52SPeter A. G. Crosthwaite #define R_SPICR (0x60 / 4) 60929d1b52SPeter A. G. Crosthwaite #define R_SPICR_TXFF_RST (1 << 5) 61929d1b52SPeter A. G. Crosthwaite #define R_SPICR_RXFF_RST (1 << 6) 62929d1b52SPeter A. G. Crosthwaite #define R_SPICR_MTI (1 << 8) 63929d1b52SPeter A. G. Crosthwaite 64929d1b52SPeter A. G. Crosthwaite #define R_SPISR (0x64 / 4) 65929d1b52SPeter A. G. Crosthwaite #define SR_TX_FULL (1 << 3) 66929d1b52SPeter A. G. Crosthwaite #define SR_TX_EMPTY (1 << 2) 67929d1b52SPeter A. G. Crosthwaite #define SR_RX_FULL (1 << 1) 68929d1b52SPeter A. G. Crosthwaite #define SR_RX_EMPTY (1 << 0) 69929d1b52SPeter A. G. Crosthwaite 70929d1b52SPeter A. G. Crosthwaite #define R_SPIDTR (0x68 / 4) 71929d1b52SPeter A. G. Crosthwaite #define R_SPIDRR (0x6C / 4) 72929d1b52SPeter A. G. Crosthwaite #define R_SPISSR (0x70 / 4) 73929d1b52SPeter A. G. Crosthwaite #define R_TX_FF_OCY (0x74 / 4) 74929d1b52SPeter A. G. Crosthwaite #define R_RX_FF_OCY (0x78 / 4) 75929d1b52SPeter A. G. Crosthwaite #define R_MAX (0x7C / 4) 76929d1b52SPeter A. G. Crosthwaite 77929d1b52SPeter A. G. Crosthwaite #define FIFO_CAPACITY 256 78929d1b52SPeter A. G. Crosthwaite 793efc10e1SAndreas Färber #define TYPE_XILINX_SPI "xlnx.xps-spi" 803efc10e1SAndreas Färber #define XILINX_SPI(obj) OBJECT_CHECK(XilinxSPI, (obj), TYPE_XILINX_SPI) 813efc10e1SAndreas Färber 82929d1b52SPeter A. G. Crosthwaite typedef struct XilinxSPI { 833efc10e1SAndreas Färber SysBusDevice parent_obj; 843efc10e1SAndreas Färber 85929d1b52SPeter A. G. Crosthwaite MemoryRegion mmio; 86929d1b52SPeter A. G. Crosthwaite 87929d1b52SPeter A. G. Crosthwaite qemu_irq irq; 88929d1b52SPeter A. G. Crosthwaite int irqline; 89929d1b52SPeter A. G. Crosthwaite 90929d1b52SPeter A. G. Crosthwaite uint8_t num_cs; 91929d1b52SPeter A. G. Crosthwaite qemu_irq *cs_lines; 92929d1b52SPeter A. G. Crosthwaite 93929d1b52SPeter A. G. Crosthwaite SSIBus *spi; 94929d1b52SPeter A. G. Crosthwaite 95929d1b52SPeter A. G. Crosthwaite Fifo8 rx_fifo; 96929d1b52SPeter A. G. Crosthwaite Fifo8 tx_fifo; 97929d1b52SPeter A. G. Crosthwaite 98929d1b52SPeter A. G. Crosthwaite uint32_t regs[R_MAX]; 99929d1b52SPeter A. G. Crosthwaite } XilinxSPI; 100929d1b52SPeter A. G. Crosthwaite 101929d1b52SPeter A. G. Crosthwaite static void txfifo_reset(XilinxSPI *s) 102929d1b52SPeter A. G. Crosthwaite { 103929d1b52SPeter A. G. Crosthwaite fifo8_reset(&s->tx_fifo); 104929d1b52SPeter A. G. Crosthwaite 105929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] &= ~SR_TX_FULL; 106929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] |= SR_TX_EMPTY; 107929d1b52SPeter A. G. Crosthwaite } 108929d1b52SPeter A. G. Crosthwaite 109929d1b52SPeter A. G. Crosthwaite static void rxfifo_reset(XilinxSPI *s) 110929d1b52SPeter A. G. Crosthwaite { 111929d1b52SPeter A. G. Crosthwaite fifo8_reset(&s->rx_fifo); 112929d1b52SPeter A. G. Crosthwaite 113929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] |= SR_RX_EMPTY; 114929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] &= ~SR_RX_FULL; 115929d1b52SPeter A. G. Crosthwaite } 116929d1b52SPeter A. G. Crosthwaite 117929d1b52SPeter A. G. Crosthwaite static void xlx_spi_update_cs(XilinxSPI *s) 118929d1b52SPeter A. G. Crosthwaite { 119929d1b52SPeter A. G. Crosthwaite int i; 120929d1b52SPeter A. G. Crosthwaite 121929d1b52SPeter A. G. Crosthwaite for (i = 0; i < s->num_cs; ++i) { 122929d1b52SPeter A. G. Crosthwaite qemu_set_irq(s->cs_lines[i], !(~s->regs[R_SPISSR] & 1 << i)); 123929d1b52SPeter A. G. Crosthwaite } 124929d1b52SPeter A. G. Crosthwaite } 125929d1b52SPeter A. G. Crosthwaite 126929d1b52SPeter A. G. Crosthwaite static void xlx_spi_update_irq(XilinxSPI *s) 127929d1b52SPeter A. G. Crosthwaite { 128929d1b52SPeter A. G. Crosthwaite uint32_t pending; 129929d1b52SPeter A. G. Crosthwaite 130929d1b52SPeter A. G. Crosthwaite s->regs[R_IPISR] |= 131929d1b52SPeter A. G. Crosthwaite (!fifo8_is_empty(&s->rx_fifo) ? IRQ_DRR_NOT_EMPTY : 0) | 132929d1b52SPeter A. G. Crosthwaite (fifo8_is_full(&s->rx_fifo) ? IRQ_DRR_FULL : 0); 133929d1b52SPeter A. G. Crosthwaite 134929d1b52SPeter A. G. Crosthwaite pending = s->regs[R_IPISR] & s->regs[R_IPIER]; 135929d1b52SPeter A. G. Crosthwaite 136929d1b52SPeter A. G. Crosthwaite pending = pending && (s->regs[R_DGIER] & R_DGIER_IE); 137929d1b52SPeter A. G. Crosthwaite pending = !!pending; 138929d1b52SPeter A. G. Crosthwaite 139929d1b52SPeter A. G. Crosthwaite /* This call lies right in the data paths so don't call the 140929d1b52SPeter A. G. Crosthwaite irq chain unless things really changed. */ 141929d1b52SPeter A. G. Crosthwaite if (pending != s->irqline) { 142929d1b52SPeter A. G. Crosthwaite s->irqline = pending; 143929d1b52SPeter A. G. Crosthwaite DB_PRINT("irq_change of state %d ISR:%x IER:%X\n", 144929d1b52SPeter A. G. Crosthwaite pending, s->regs[R_IPISR], s->regs[R_IPIER]); 145929d1b52SPeter A. G. Crosthwaite qemu_set_irq(s->irq, pending); 146929d1b52SPeter A. G. Crosthwaite } 147929d1b52SPeter A. G. Crosthwaite 148929d1b52SPeter A. G. Crosthwaite } 149929d1b52SPeter A. G. Crosthwaite 150929d1b52SPeter A. G. Crosthwaite static void xlx_spi_do_reset(XilinxSPI *s) 151929d1b52SPeter A. G. Crosthwaite { 152929d1b52SPeter A. G. Crosthwaite memset(s->regs, 0, sizeof s->regs); 153929d1b52SPeter A. G. Crosthwaite 154929d1b52SPeter A. G. Crosthwaite rxfifo_reset(s); 155929d1b52SPeter A. G. Crosthwaite txfifo_reset(s); 156929d1b52SPeter A. G. Crosthwaite 157929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISSR] = ~0; 158929d1b52SPeter A. G. Crosthwaite xlx_spi_update_irq(s); 159929d1b52SPeter A. G. Crosthwaite xlx_spi_update_cs(s); 160929d1b52SPeter A. G. Crosthwaite } 161929d1b52SPeter A. G. Crosthwaite 162929d1b52SPeter A. G. Crosthwaite static void xlx_spi_reset(DeviceState *d) 163929d1b52SPeter A. G. Crosthwaite { 1643efc10e1SAndreas Färber xlx_spi_do_reset(XILINX_SPI(d)); 165929d1b52SPeter A. G. Crosthwaite } 166929d1b52SPeter A. G. Crosthwaite 167929d1b52SPeter A. G. Crosthwaite static inline int spi_master_enabled(XilinxSPI *s) 168929d1b52SPeter A. G. Crosthwaite { 169929d1b52SPeter A. G. Crosthwaite return !(s->regs[R_SPICR] & R_SPICR_MTI); 170929d1b52SPeter A. G. Crosthwaite } 171929d1b52SPeter A. G. Crosthwaite 172929d1b52SPeter A. G. Crosthwaite static void spi_flush_txfifo(XilinxSPI *s) 173929d1b52SPeter A. G. Crosthwaite { 174929d1b52SPeter A. G. Crosthwaite uint32_t tx; 175929d1b52SPeter A. G. Crosthwaite uint32_t rx; 176929d1b52SPeter A. G. Crosthwaite 177929d1b52SPeter A. G. Crosthwaite while (!fifo8_is_empty(&s->tx_fifo)) { 178929d1b52SPeter A. G. Crosthwaite tx = (uint32_t)fifo8_pop(&s->tx_fifo); 179929d1b52SPeter A. G. Crosthwaite DB_PRINT("data tx:%x\n", tx); 180929d1b52SPeter A. G. Crosthwaite rx = ssi_transfer(s->spi, tx); 181929d1b52SPeter A. G. Crosthwaite DB_PRINT("data rx:%x\n", rx); 182929d1b52SPeter A. G. Crosthwaite if (fifo8_is_full(&s->rx_fifo)) { 183929d1b52SPeter A. G. Crosthwaite s->regs[R_IPISR] |= IRQ_DRR_OVERRUN; 184929d1b52SPeter A. G. Crosthwaite } else { 185929d1b52SPeter A. G. Crosthwaite fifo8_push(&s->rx_fifo, (uint8_t)rx); 186929d1b52SPeter A. G. Crosthwaite if (fifo8_is_full(&s->rx_fifo)) { 187929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] |= SR_RX_FULL; 188929d1b52SPeter A. G. Crosthwaite s->regs[R_IPISR] |= IRQ_DRR_FULL; 189929d1b52SPeter A. G. Crosthwaite } 190929d1b52SPeter A. G. Crosthwaite } 191929d1b52SPeter A. G. Crosthwaite 192929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] &= ~SR_RX_EMPTY; 193929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] &= ~SR_TX_FULL; 194929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] |= SR_TX_EMPTY; 195929d1b52SPeter A. G. Crosthwaite 196929d1b52SPeter A. G. Crosthwaite s->regs[R_IPISR] |= IRQ_DTR_EMPTY; 197929d1b52SPeter A. G. Crosthwaite s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY; 198929d1b52SPeter A. G. Crosthwaite } 199929d1b52SPeter A. G. Crosthwaite 200929d1b52SPeter A. G. Crosthwaite } 201929d1b52SPeter A. G. Crosthwaite 202929d1b52SPeter A. G. Crosthwaite static uint64_t 203a8170e5eSAvi Kivity spi_read(void *opaque, hwaddr addr, unsigned int size) 204929d1b52SPeter A. G. Crosthwaite { 205929d1b52SPeter A. G. Crosthwaite XilinxSPI *s = opaque; 206929d1b52SPeter A. G. Crosthwaite uint32_t r = 0; 207929d1b52SPeter A. G. Crosthwaite 208929d1b52SPeter A. G. Crosthwaite addr >>= 2; 209929d1b52SPeter A. G. Crosthwaite switch (addr) { 210929d1b52SPeter A. G. Crosthwaite case R_SPIDRR: 211929d1b52SPeter A. G. Crosthwaite if (fifo8_is_empty(&s->rx_fifo)) { 212929d1b52SPeter A. G. Crosthwaite DB_PRINT("Read from empty FIFO!\n"); 213929d1b52SPeter A. G. Crosthwaite return 0xdeadbeef; 214929d1b52SPeter A. G. Crosthwaite } 215929d1b52SPeter A. G. Crosthwaite 216929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] &= ~SR_RX_FULL; 217929d1b52SPeter A. G. Crosthwaite r = fifo8_pop(&s->rx_fifo); 218929d1b52SPeter A. G. Crosthwaite if (fifo8_is_empty(&s->rx_fifo)) { 219929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] |= SR_RX_EMPTY; 220929d1b52SPeter A. G. Crosthwaite } 221929d1b52SPeter A. G. Crosthwaite break; 222929d1b52SPeter A. G. Crosthwaite 223929d1b52SPeter A. G. Crosthwaite case R_SPISR: 224929d1b52SPeter A. G. Crosthwaite r = s->regs[addr]; 225929d1b52SPeter A. G. Crosthwaite break; 226929d1b52SPeter A. G. Crosthwaite 227929d1b52SPeter A. G. Crosthwaite default: 228929d1b52SPeter A. G. Crosthwaite if (addr < ARRAY_SIZE(s->regs)) { 229929d1b52SPeter A. G. Crosthwaite r = s->regs[addr]; 230929d1b52SPeter A. G. Crosthwaite } 231929d1b52SPeter A. G. Crosthwaite break; 232929d1b52SPeter A. G. Crosthwaite 233929d1b52SPeter A. G. Crosthwaite } 234929d1b52SPeter A. G. Crosthwaite DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, r); 235929d1b52SPeter A. G. Crosthwaite xlx_spi_update_irq(s); 236929d1b52SPeter A. G. Crosthwaite return r; 237929d1b52SPeter A. G. Crosthwaite } 238929d1b52SPeter A. G. Crosthwaite 239929d1b52SPeter A. G. Crosthwaite static void 240a8170e5eSAvi Kivity spi_write(void *opaque, hwaddr addr, 241929d1b52SPeter A. G. Crosthwaite uint64_t val64, unsigned int size) 242929d1b52SPeter A. G. Crosthwaite { 243929d1b52SPeter A. G. Crosthwaite XilinxSPI *s = opaque; 244929d1b52SPeter A. G. Crosthwaite uint32_t value = val64; 245929d1b52SPeter A. G. Crosthwaite 246929d1b52SPeter A. G. Crosthwaite DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, value); 247929d1b52SPeter A. G. Crosthwaite addr >>= 2; 248929d1b52SPeter A. G. Crosthwaite switch (addr) { 249929d1b52SPeter A. G. Crosthwaite case R_SRR: 250929d1b52SPeter A. G. Crosthwaite if (value != 0xa) { 251929d1b52SPeter A. G. Crosthwaite DB_PRINT("Invalid write to SRR %x\n", value); 252929d1b52SPeter A. G. Crosthwaite } else { 253929d1b52SPeter A. G. Crosthwaite xlx_spi_do_reset(s); 254929d1b52SPeter A. G. Crosthwaite } 255929d1b52SPeter A. G. Crosthwaite break; 256929d1b52SPeter A. G. Crosthwaite 257929d1b52SPeter A. G. Crosthwaite case R_SPIDTR: 258929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] &= ~SR_TX_EMPTY; 259929d1b52SPeter A. G. Crosthwaite fifo8_push(&s->tx_fifo, (uint8_t)value); 260929d1b52SPeter A. G. Crosthwaite if (fifo8_is_full(&s->tx_fifo)) { 261929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] |= SR_TX_FULL; 262929d1b52SPeter A. G. Crosthwaite } 263929d1b52SPeter A. G. Crosthwaite if (!spi_master_enabled(s)) { 264929d1b52SPeter A. G. Crosthwaite goto done; 265929d1b52SPeter A. G. Crosthwaite } else { 266929d1b52SPeter A. G. Crosthwaite DB_PRINT("DTR and master enabled\n"); 267929d1b52SPeter A. G. Crosthwaite } 268929d1b52SPeter A. G. Crosthwaite spi_flush_txfifo(s); 269929d1b52SPeter A. G. Crosthwaite break; 270929d1b52SPeter A. G. Crosthwaite 271929d1b52SPeter A. G. Crosthwaite case R_SPISR: 272929d1b52SPeter A. G. Crosthwaite DB_PRINT("Invalid write to SPISR %x\n", value); 273929d1b52SPeter A. G. Crosthwaite break; 274929d1b52SPeter A. G. Crosthwaite 275929d1b52SPeter A. G. Crosthwaite case R_IPISR: 276929d1b52SPeter A. G. Crosthwaite /* Toggle the bits. */ 277929d1b52SPeter A. G. Crosthwaite s->regs[addr] ^= value; 278929d1b52SPeter A. G. Crosthwaite break; 279929d1b52SPeter A. G. Crosthwaite 280929d1b52SPeter A. G. Crosthwaite /* Slave Select Register. */ 281929d1b52SPeter A. G. Crosthwaite case R_SPISSR: 282929d1b52SPeter A. G. Crosthwaite s->regs[addr] = value; 283929d1b52SPeter A. G. Crosthwaite xlx_spi_update_cs(s); 284929d1b52SPeter A. G. Crosthwaite break; 285929d1b52SPeter A. G. Crosthwaite 286929d1b52SPeter A. G. Crosthwaite case R_SPICR: 287929d1b52SPeter A. G. Crosthwaite /* FIXME: reset irq and sr state to empty queues. */ 288929d1b52SPeter A. G. Crosthwaite if (value & R_SPICR_RXFF_RST) { 289929d1b52SPeter A. G. Crosthwaite rxfifo_reset(s); 290929d1b52SPeter A. G. Crosthwaite } 291929d1b52SPeter A. G. Crosthwaite 292929d1b52SPeter A. G. Crosthwaite if (value & R_SPICR_TXFF_RST) { 293929d1b52SPeter A. G. Crosthwaite txfifo_reset(s); 294929d1b52SPeter A. G. Crosthwaite } 295929d1b52SPeter A. G. Crosthwaite value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST); 296929d1b52SPeter A. G. Crosthwaite s->regs[addr] = value; 297929d1b52SPeter A. G. Crosthwaite 298929d1b52SPeter A. G. Crosthwaite if (!(value & R_SPICR_MTI)) { 299929d1b52SPeter A. G. Crosthwaite spi_flush_txfifo(s); 300929d1b52SPeter A. G. Crosthwaite } 301929d1b52SPeter A. G. Crosthwaite break; 302929d1b52SPeter A. G. Crosthwaite 303929d1b52SPeter A. G. Crosthwaite default: 304929d1b52SPeter A. G. Crosthwaite if (addr < ARRAY_SIZE(s->regs)) { 305929d1b52SPeter A. G. Crosthwaite s->regs[addr] = value; 306929d1b52SPeter A. G. Crosthwaite } 307929d1b52SPeter A. G. Crosthwaite break; 308929d1b52SPeter A. G. Crosthwaite } 309929d1b52SPeter A. G. Crosthwaite 310929d1b52SPeter A. G. Crosthwaite done: 311929d1b52SPeter A. G. Crosthwaite xlx_spi_update_irq(s); 312929d1b52SPeter A. G. Crosthwaite } 313929d1b52SPeter A. G. Crosthwaite 314929d1b52SPeter A. G. Crosthwaite static const MemoryRegionOps spi_ops = { 315929d1b52SPeter A. G. Crosthwaite .read = spi_read, 316929d1b52SPeter A. G. Crosthwaite .write = spi_write, 317929d1b52SPeter A. G. Crosthwaite .endianness = DEVICE_NATIVE_ENDIAN, 318929d1b52SPeter A. G. Crosthwaite .valid = { 319929d1b52SPeter A. G. Crosthwaite .min_access_size = 4, 320929d1b52SPeter A. G. Crosthwaite .max_access_size = 4 321929d1b52SPeter A. G. Crosthwaite } 322929d1b52SPeter A. G. Crosthwaite }; 323929d1b52SPeter A. G. Crosthwaite 324a7e1562cSPhilippe Mathieu-Daudé static void xilinx_spi_realize(DeviceState *dev, Error **errp) 325929d1b52SPeter A. G. Crosthwaite { 326a7e1562cSPhilippe Mathieu-Daudé SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 3273efc10e1SAndreas Färber XilinxSPI *s = XILINX_SPI(dev); 328929d1b52SPeter A. G. Crosthwaite int i; 329929d1b52SPeter A. G. Crosthwaite 330929d1b52SPeter A. G. Crosthwaite DB_PRINT("\n"); 331b4ae3cfaSPeter Crosthwaite 3323efc10e1SAndreas Färber s->spi = ssi_create_bus(dev, "spi"); 333b4ae3cfaSPeter Crosthwaite 3343efc10e1SAndreas Färber sysbus_init_irq(sbd, &s->irq); 335c75f3c04SPeter Crosthwaite s->cs_lines = g_new0(qemu_irq, s->num_cs); 3363efc10e1SAndreas Färber ssi_auto_connect_slaves(dev, s->cs_lines, s->spi); 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; 374929d1b52SPeter A. G. Crosthwaite dc->props = 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