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