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" 28*e87c93dfSPhilippe Mathieu-Daudé #include "qapi/error.h" 2983c9f4caSPaolo Bonzini #include "hw/sysbus.h" 30d6454270SMarkus Armbruster #include "migration/vmstate.h" 310b8fa32fSMarkus Armbruster #include "qemu/module.h" 32fd7f0d66SPaolo Bonzini #include "qemu/fifo8.h" 33929d1b52SPeter A. G. Crosthwaite 3464552b6bSMarkus Armbruster #include "hw/irq.h" 35a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 36*e87c93dfSPhilippe Mathieu-Daudé #include "hw/qdev-properties-system.h" 378fd06719SAlistair Francis #include "hw/ssi/ssi.h" 38db1015e9SEduardo Habkost #include "qom/object.h" 39929d1b52SPeter A. G. Crosthwaite 40929d1b52SPeter A. G. Crosthwaite #ifdef XILINX_SPI_ERR_DEBUG 41929d1b52SPeter A. G. Crosthwaite #define DB_PRINT(...) do { \ 42929d1b52SPeter A. G. Crosthwaite fprintf(stderr, ": %s: ", __func__); \ 43929d1b52SPeter A. G. Crosthwaite fprintf(stderr, ## __VA_ARGS__); \ 442562755eSEric Blake } while (0) 45929d1b52SPeter A. G. Crosthwaite #else 46929d1b52SPeter A. G. Crosthwaite #define DB_PRINT(...) 47929d1b52SPeter A. G. Crosthwaite #endif 48929d1b52SPeter A. G. Crosthwaite 49929d1b52SPeter A. G. Crosthwaite #define R_DGIER (0x1c / 4) 50929d1b52SPeter A. G. Crosthwaite #define R_DGIER_IE (1 << 31) 51929d1b52SPeter A. G. Crosthwaite 52929d1b52SPeter A. G. Crosthwaite #define R_IPISR (0x20 / 4) 53929d1b52SPeter A. G. Crosthwaite #define IRQ_DRR_NOT_EMPTY (1 << (31 - 23)) 54929d1b52SPeter A. G. Crosthwaite #define IRQ_DRR_OVERRUN (1 << (31 - 26)) 55929d1b52SPeter A. G. Crosthwaite #define IRQ_DRR_FULL (1 << (31 - 27)) 56929d1b52SPeter A. G. Crosthwaite #define IRQ_TX_FF_HALF_EMPTY (1 << 6) 57929d1b52SPeter A. G. Crosthwaite #define IRQ_DTR_UNDERRUN (1 << 3) 58929d1b52SPeter A. G. Crosthwaite #define IRQ_DTR_EMPTY (1 << (31 - 29)) 59929d1b52SPeter A. G. Crosthwaite 60929d1b52SPeter A. G. Crosthwaite #define R_IPIER (0x28 / 4) 61929d1b52SPeter A. G. Crosthwaite #define R_SRR (0x40 / 4) 62929d1b52SPeter A. G. Crosthwaite #define R_SPICR (0x60 / 4) 63929d1b52SPeter A. G. Crosthwaite #define R_SPICR_TXFF_RST (1 << 5) 64929d1b52SPeter A. G. Crosthwaite #define R_SPICR_RXFF_RST (1 << 6) 65929d1b52SPeter A. G. Crosthwaite #define R_SPICR_MTI (1 << 8) 66929d1b52SPeter A. G. Crosthwaite 67929d1b52SPeter A. G. Crosthwaite #define R_SPISR (0x64 / 4) 68929d1b52SPeter A. G. Crosthwaite #define SR_TX_FULL (1 << 3) 69929d1b52SPeter A. G. Crosthwaite #define SR_TX_EMPTY (1 << 2) 70929d1b52SPeter A. G. Crosthwaite #define SR_RX_FULL (1 << 1) 71929d1b52SPeter A. G. Crosthwaite #define SR_RX_EMPTY (1 << 0) 72929d1b52SPeter A. G. Crosthwaite 73929d1b52SPeter A. G. Crosthwaite #define R_SPIDTR (0x68 / 4) 74929d1b52SPeter A. G. Crosthwaite #define R_SPIDRR (0x6C / 4) 75929d1b52SPeter A. G. Crosthwaite #define R_SPISSR (0x70 / 4) 76929d1b52SPeter A. G. Crosthwaite #define R_TX_FF_OCY (0x74 / 4) 77929d1b52SPeter A. G. Crosthwaite #define R_RX_FF_OCY (0x78 / 4) 78929d1b52SPeter A. G. Crosthwaite #define R_MAX (0x7C / 4) 79929d1b52SPeter A. G. Crosthwaite 80929d1b52SPeter A. G. Crosthwaite #define FIFO_CAPACITY 256 81929d1b52SPeter A. G. Crosthwaite 823efc10e1SAndreas Färber #define TYPE_XILINX_SPI "xlnx.xps-spi" 838063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(XilinxSPI, XILINX_SPI) 843efc10e1SAndreas Färber 85db1015e9SEduardo Habkost struct XilinxSPI { 863efc10e1SAndreas Färber SysBusDevice parent_obj; 873efc10e1SAndreas Färber 88*e87c93dfSPhilippe Mathieu-Daudé EndianMode model_endianness; 89929d1b52SPeter A. G. Crosthwaite MemoryRegion mmio; 90929d1b52SPeter A. G. Crosthwaite 91929d1b52SPeter A. G. Crosthwaite qemu_irq irq; 92929d1b52SPeter A. G. Crosthwaite int irqline; 93929d1b52SPeter A. G. Crosthwaite 94929d1b52SPeter A. G. Crosthwaite uint8_t num_cs; 95929d1b52SPeter A. G. Crosthwaite qemu_irq *cs_lines; 96929d1b52SPeter A. G. Crosthwaite 97929d1b52SPeter A. G. Crosthwaite SSIBus *spi; 98929d1b52SPeter A. G. Crosthwaite 99929d1b52SPeter A. G. Crosthwaite Fifo8 rx_fifo; 100929d1b52SPeter A. G. Crosthwaite Fifo8 tx_fifo; 101929d1b52SPeter A. G. Crosthwaite 102929d1b52SPeter A. G. Crosthwaite uint32_t regs[R_MAX]; 103db1015e9SEduardo Habkost }; 104929d1b52SPeter A. G. Crosthwaite 105929d1b52SPeter A. G. Crosthwaite static void txfifo_reset(XilinxSPI *s) 106929d1b52SPeter A. G. Crosthwaite { 107929d1b52SPeter A. G. Crosthwaite fifo8_reset(&s->tx_fifo); 108929d1b52SPeter A. G. Crosthwaite 109929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] &= ~SR_TX_FULL; 110929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] |= SR_TX_EMPTY; 111929d1b52SPeter A. G. Crosthwaite } 112929d1b52SPeter A. G. Crosthwaite 113929d1b52SPeter A. G. Crosthwaite static void rxfifo_reset(XilinxSPI *s) 114929d1b52SPeter A. G. Crosthwaite { 115929d1b52SPeter A. G. Crosthwaite fifo8_reset(&s->rx_fifo); 116929d1b52SPeter A. G. Crosthwaite 117929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] |= SR_RX_EMPTY; 118929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] &= ~SR_RX_FULL; 119929d1b52SPeter A. G. Crosthwaite } 120929d1b52SPeter A. G. Crosthwaite 121929d1b52SPeter A. G. Crosthwaite static void xlx_spi_update_cs(XilinxSPI *s) 122929d1b52SPeter A. G. Crosthwaite { 123929d1b52SPeter A. G. Crosthwaite int i; 124929d1b52SPeter A. G. Crosthwaite 125929d1b52SPeter A. G. Crosthwaite for (i = 0; i < s->num_cs; ++i) { 126929d1b52SPeter A. G. Crosthwaite qemu_set_irq(s->cs_lines[i], !(~s->regs[R_SPISSR] & 1 << i)); 127929d1b52SPeter A. G. Crosthwaite } 128929d1b52SPeter A. G. Crosthwaite } 129929d1b52SPeter A. G. Crosthwaite 130929d1b52SPeter A. G. Crosthwaite static void xlx_spi_update_irq(XilinxSPI *s) 131929d1b52SPeter A. G. Crosthwaite { 132929d1b52SPeter A. G. Crosthwaite uint32_t pending; 133929d1b52SPeter A. G. Crosthwaite 134929d1b52SPeter A. G. Crosthwaite s->regs[R_IPISR] |= 135929d1b52SPeter A. G. Crosthwaite (!fifo8_is_empty(&s->rx_fifo) ? IRQ_DRR_NOT_EMPTY : 0) | 136929d1b52SPeter A. G. Crosthwaite (fifo8_is_full(&s->rx_fifo) ? IRQ_DRR_FULL : 0); 137929d1b52SPeter A. G. Crosthwaite 138929d1b52SPeter A. G. Crosthwaite pending = s->regs[R_IPISR] & s->regs[R_IPIER]; 139929d1b52SPeter A. G. Crosthwaite 140929d1b52SPeter A. G. Crosthwaite pending = pending && (s->regs[R_DGIER] & R_DGIER_IE); 141929d1b52SPeter A. G. Crosthwaite pending = !!pending; 142929d1b52SPeter A. G. Crosthwaite 143929d1b52SPeter A. G. Crosthwaite /* This call lies right in the data paths so don't call the 144929d1b52SPeter A. G. Crosthwaite irq chain unless things really changed. */ 145929d1b52SPeter A. G. Crosthwaite if (pending != s->irqline) { 146929d1b52SPeter A. G. Crosthwaite s->irqline = pending; 1479df0a972SAlexChen DB_PRINT("irq_change of state %u ISR:%x IER:%X\n", 148929d1b52SPeter A. G. Crosthwaite pending, s->regs[R_IPISR], s->regs[R_IPIER]); 149929d1b52SPeter A. G. Crosthwaite qemu_set_irq(s->irq, pending); 150929d1b52SPeter A. G. Crosthwaite } 151929d1b52SPeter A. G. Crosthwaite 152929d1b52SPeter A. G. Crosthwaite } 153929d1b52SPeter A. G. Crosthwaite 154929d1b52SPeter A. G. Crosthwaite static void xlx_spi_do_reset(XilinxSPI *s) 155929d1b52SPeter A. G. Crosthwaite { 156929d1b52SPeter A. G. Crosthwaite memset(s->regs, 0, sizeof s->regs); 157929d1b52SPeter A. G. Crosthwaite 158929d1b52SPeter A. G. Crosthwaite rxfifo_reset(s); 159929d1b52SPeter A. G. Crosthwaite txfifo_reset(s); 160929d1b52SPeter A. G. Crosthwaite 161929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISSR] = ~0; 162a0eaa126SChris Rauer s->regs[R_SPICR] = R_SPICR_MTI; 163929d1b52SPeter A. G. Crosthwaite xlx_spi_update_irq(s); 164929d1b52SPeter A. G. Crosthwaite xlx_spi_update_cs(s); 165929d1b52SPeter A. G. Crosthwaite } 166929d1b52SPeter A. G. Crosthwaite 167929d1b52SPeter A. G. Crosthwaite static void xlx_spi_reset(DeviceState *d) 168929d1b52SPeter A. G. Crosthwaite { 1693efc10e1SAndreas Färber xlx_spi_do_reset(XILINX_SPI(d)); 170929d1b52SPeter A. G. Crosthwaite } 171929d1b52SPeter A. G. Crosthwaite 172929d1b52SPeter A. G. Crosthwaite static inline int spi_master_enabled(XilinxSPI *s) 173929d1b52SPeter A. G. Crosthwaite { 174929d1b52SPeter A. G. Crosthwaite return !(s->regs[R_SPICR] & R_SPICR_MTI); 175929d1b52SPeter A. G. Crosthwaite } 176929d1b52SPeter A. G. Crosthwaite 177929d1b52SPeter A. G. Crosthwaite static void spi_flush_txfifo(XilinxSPI *s) 178929d1b52SPeter A. G. Crosthwaite { 179929d1b52SPeter A. G. Crosthwaite uint32_t tx; 180929d1b52SPeter A. G. Crosthwaite uint32_t rx; 181929d1b52SPeter A. G. Crosthwaite 182929d1b52SPeter A. G. Crosthwaite while (!fifo8_is_empty(&s->tx_fifo)) { 183929d1b52SPeter A. G. Crosthwaite tx = (uint32_t)fifo8_pop(&s->tx_fifo); 184929d1b52SPeter A. G. Crosthwaite DB_PRINT("data tx:%x\n", tx); 185929d1b52SPeter A. G. Crosthwaite rx = ssi_transfer(s->spi, tx); 186929d1b52SPeter A. G. Crosthwaite DB_PRINT("data rx:%x\n", rx); 187929d1b52SPeter A. G. Crosthwaite if (fifo8_is_full(&s->rx_fifo)) { 188929d1b52SPeter A. G. Crosthwaite s->regs[R_IPISR] |= IRQ_DRR_OVERRUN; 189929d1b52SPeter A. G. Crosthwaite } else { 190929d1b52SPeter A. G. Crosthwaite fifo8_push(&s->rx_fifo, (uint8_t)rx); 191929d1b52SPeter A. G. Crosthwaite if (fifo8_is_full(&s->rx_fifo)) { 192929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] |= SR_RX_FULL; 193929d1b52SPeter A. G. Crosthwaite s->regs[R_IPISR] |= IRQ_DRR_FULL; 194929d1b52SPeter A. G. Crosthwaite } 195929d1b52SPeter A. G. Crosthwaite } 196929d1b52SPeter A. G. Crosthwaite 197929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] &= ~SR_RX_EMPTY; 198929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] &= ~SR_TX_FULL; 199929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] |= SR_TX_EMPTY; 200929d1b52SPeter A. G. Crosthwaite 201929d1b52SPeter A. G. Crosthwaite s->regs[R_IPISR] |= IRQ_DTR_EMPTY; 202929d1b52SPeter A. G. Crosthwaite s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY; 203929d1b52SPeter A. G. Crosthwaite } 204929d1b52SPeter A. G. Crosthwaite 205929d1b52SPeter A. G. Crosthwaite } 206929d1b52SPeter A. G. Crosthwaite 207929d1b52SPeter A. G. Crosthwaite static uint64_t 208a8170e5eSAvi Kivity spi_read(void *opaque, hwaddr addr, unsigned int size) 209929d1b52SPeter A. G. Crosthwaite { 210929d1b52SPeter A. G. Crosthwaite XilinxSPI *s = opaque; 211929d1b52SPeter A. G. Crosthwaite uint32_t r = 0; 212929d1b52SPeter A. G. Crosthwaite 213929d1b52SPeter A. G. Crosthwaite addr >>= 2; 214929d1b52SPeter A. G. Crosthwaite switch (addr) { 215929d1b52SPeter A. G. Crosthwaite case R_SPIDRR: 216929d1b52SPeter A. G. Crosthwaite if (fifo8_is_empty(&s->rx_fifo)) { 217929d1b52SPeter A. G. Crosthwaite DB_PRINT("Read from empty FIFO!\n"); 218929d1b52SPeter A. G. Crosthwaite return 0xdeadbeef; 219929d1b52SPeter A. G. Crosthwaite } 220929d1b52SPeter A. G. Crosthwaite 221929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] &= ~SR_RX_FULL; 222929d1b52SPeter A. G. Crosthwaite r = fifo8_pop(&s->rx_fifo); 223929d1b52SPeter A. G. Crosthwaite if (fifo8_is_empty(&s->rx_fifo)) { 224929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] |= SR_RX_EMPTY; 225929d1b52SPeter A. G. Crosthwaite } 226929d1b52SPeter A. G. Crosthwaite break; 227929d1b52SPeter A. G. Crosthwaite 228929d1b52SPeter A. G. Crosthwaite case R_SPISR: 229929d1b52SPeter A. G. Crosthwaite r = s->regs[addr]; 230929d1b52SPeter A. G. Crosthwaite break; 231929d1b52SPeter A. G. Crosthwaite 232929d1b52SPeter A. G. Crosthwaite default: 233929d1b52SPeter A. G. Crosthwaite if (addr < ARRAY_SIZE(s->regs)) { 234929d1b52SPeter A. G. Crosthwaite r = s->regs[addr]; 235929d1b52SPeter A. G. Crosthwaite } 236929d1b52SPeter A. G. Crosthwaite break; 237929d1b52SPeter A. G. Crosthwaite 238929d1b52SPeter A. G. Crosthwaite } 239883f2c59SPhilippe Mathieu-Daudé DB_PRINT("addr=" HWADDR_FMT_plx " = %x\n", addr * 4, r); 240929d1b52SPeter A. G. Crosthwaite xlx_spi_update_irq(s); 241929d1b52SPeter A. G. Crosthwaite return r; 242929d1b52SPeter A. G. Crosthwaite } 243929d1b52SPeter A. G. Crosthwaite 244929d1b52SPeter A. G. Crosthwaite static void 245a8170e5eSAvi Kivity spi_write(void *opaque, hwaddr addr, 246929d1b52SPeter A. G. Crosthwaite uint64_t val64, unsigned int size) 247929d1b52SPeter A. G. Crosthwaite { 248929d1b52SPeter A. G. Crosthwaite XilinxSPI *s = opaque; 249929d1b52SPeter A. G. Crosthwaite uint32_t value = val64; 250929d1b52SPeter A. G. Crosthwaite 251883f2c59SPhilippe Mathieu-Daudé DB_PRINT("addr=" HWADDR_FMT_plx " = %x\n", addr, value); 252929d1b52SPeter A. G. Crosthwaite addr >>= 2; 253929d1b52SPeter A. G. Crosthwaite switch (addr) { 254929d1b52SPeter A. G. Crosthwaite case R_SRR: 255929d1b52SPeter A. G. Crosthwaite if (value != 0xa) { 256929d1b52SPeter A. G. Crosthwaite DB_PRINT("Invalid write to SRR %x\n", value); 257929d1b52SPeter A. G. Crosthwaite } else { 258929d1b52SPeter A. G. Crosthwaite xlx_spi_do_reset(s); 259929d1b52SPeter A. G. Crosthwaite } 260929d1b52SPeter A. G. Crosthwaite break; 261929d1b52SPeter A. G. Crosthwaite 262929d1b52SPeter A. G. Crosthwaite case R_SPIDTR: 263929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] &= ~SR_TX_EMPTY; 264929d1b52SPeter A. G. Crosthwaite fifo8_push(&s->tx_fifo, (uint8_t)value); 265929d1b52SPeter A. G. Crosthwaite if (fifo8_is_full(&s->tx_fifo)) { 266929d1b52SPeter A. G. Crosthwaite s->regs[R_SPISR] |= SR_TX_FULL; 267929d1b52SPeter A. G. Crosthwaite } 268929d1b52SPeter A. G. Crosthwaite if (!spi_master_enabled(s)) { 269929d1b52SPeter A. G. Crosthwaite goto done; 270929d1b52SPeter A. G. Crosthwaite } else { 271929d1b52SPeter A. G. Crosthwaite DB_PRINT("DTR and master enabled\n"); 272929d1b52SPeter A. G. Crosthwaite } 273929d1b52SPeter A. G. Crosthwaite spi_flush_txfifo(s); 274929d1b52SPeter A. G. Crosthwaite break; 275929d1b52SPeter A. G. Crosthwaite 276929d1b52SPeter A. G. Crosthwaite case R_SPISR: 277929d1b52SPeter A. G. Crosthwaite DB_PRINT("Invalid write to SPISR %x\n", value); 278929d1b52SPeter A. G. Crosthwaite break; 279929d1b52SPeter A. G. Crosthwaite 280929d1b52SPeter A. G. Crosthwaite case R_IPISR: 281929d1b52SPeter A. G. Crosthwaite /* Toggle the bits. */ 282929d1b52SPeter A. G. Crosthwaite s->regs[addr] ^= value; 283929d1b52SPeter A. G. Crosthwaite break; 284929d1b52SPeter A. G. Crosthwaite 285929d1b52SPeter A. G. Crosthwaite /* Slave Select Register. */ 286929d1b52SPeter A. G. Crosthwaite case R_SPISSR: 287929d1b52SPeter A. G. Crosthwaite s->regs[addr] = value; 288929d1b52SPeter A. G. Crosthwaite xlx_spi_update_cs(s); 289929d1b52SPeter A. G. Crosthwaite break; 290929d1b52SPeter A. G. Crosthwaite 291929d1b52SPeter A. G. Crosthwaite case R_SPICR: 292929d1b52SPeter A. G. Crosthwaite /* FIXME: reset irq and sr state to empty queues. */ 293929d1b52SPeter A. G. Crosthwaite if (value & R_SPICR_RXFF_RST) { 294929d1b52SPeter A. G. Crosthwaite rxfifo_reset(s); 295929d1b52SPeter A. G. Crosthwaite } 296929d1b52SPeter A. G. Crosthwaite 297929d1b52SPeter A. G. Crosthwaite if (value & R_SPICR_TXFF_RST) { 298929d1b52SPeter A. G. Crosthwaite txfifo_reset(s); 299929d1b52SPeter A. G. Crosthwaite } 300929d1b52SPeter A. G. Crosthwaite value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST); 301929d1b52SPeter A. G. Crosthwaite s->regs[addr] = value; 302929d1b52SPeter A. G. Crosthwaite 303929d1b52SPeter A. G. Crosthwaite if (!(value & R_SPICR_MTI)) { 304929d1b52SPeter A. G. Crosthwaite spi_flush_txfifo(s); 305929d1b52SPeter A. G. Crosthwaite } 306929d1b52SPeter A. G. Crosthwaite break; 307929d1b52SPeter A. G. Crosthwaite 308929d1b52SPeter A. G. Crosthwaite default: 309929d1b52SPeter A. G. Crosthwaite if (addr < ARRAY_SIZE(s->regs)) { 310929d1b52SPeter A. G. Crosthwaite s->regs[addr] = value; 311929d1b52SPeter A. G. Crosthwaite } 312929d1b52SPeter A. G. Crosthwaite break; 313929d1b52SPeter A. G. Crosthwaite } 314929d1b52SPeter A. G. Crosthwaite 315929d1b52SPeter A. G. Crosthwaite done: 316929d1b52SPeter A. G. Crosthwaite xlx_spi_update_irq(s); 317929d1b52SPeter A. G. Crosthwaite } 318929d1b52SPeter A. G. Crosthwaite 319*e87c93dfSPhilippe Mathieu-Daudé static const MemoryRegionOps spi_ops[2] = { 320*e87c93dfSPhilippe Mathieu-Daudé [0 ... 1] = { 321929d1b52SPeter A. G. Crosthwaite .read = spi_read, 322929d1b52SPeter A. G. Crosthwaite .write = spi_write, 323929d1b52SPeter A. G. Crosthwaite .valid = { 324929d1b52SPeter A. G. Crosthwaite .min_access_size = 4, 325*e87c93dfSPhilippe Mathieu-Daudé .max_access_size = 4, 326*e87c93dfSPhilippe Mathieu-Daudé }, 327*e87c93dfSPhilippe Mathieu-Daudé }, 328*e87c93dfSPhilippe Mathieu-Daudé [0].endianness = DEVICE_LITTLE_ENDIAN, 329*e87c93dfSPhilippe Mathieu-Daudé [1].endianness = DEVICE_BIG_ENDIAN, 330929d1b52SPeter A. G. Crosthwaite }; 331929d1b52SPeter A. G. Crosthwaite 332a7e1562cSPhilippe Mathieu-Daudé static void xilinx_spi_realize(DeviceState *dev, Error **errp) 333929d1b52SPeter A. G. Crosthwaite { 334a7e1562cSPhilippe Mathieu-Daudé SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 3353efc10e1SAndreas Färber XilinxSPI *s = XILINX_SPI(dev); 336929d1b52SPeter A. G. Crosthwaite int i; 337929d1b52SPeter A. G. Crosthwaite 338*e87c93dfSPhilippe Mathieu-Daudé if (s->model_endianness == ENDIAN_MODE_UNSPECIFIED) { 339*e87c93dfSPhilippe Mathieu-Daudé error_setg(errp, TYPE_XILINX_SPI " property 'endianness'" 340*e87c93dfSPhilippe Mathieu-Daudé " must be set to 'big' or 'little'"); 341*e87c93dfSPhilippe Mathieu-Daudé return; 342*e87c93dfSPhilippe Mathieu-Daudé } 343*e87c93dfSPhilippe Mathieu-Daudé 344929d1b52SPeter A. G. Crosthwaite DB_PRINT("\n"); 345b4ae3cfaSPeter Crosthwaite 3463efc10e1SAndreas Färber s->spi = ssi_create_bus(dev, "spi"); 347b4ae3cfaSPeter Crosthwaite 3483efc10e1SAndreas Färber sysbus_init_irq(sbd, &s->irq); 349c75f3c04SPeter Crosthwaite s->cs_lines = g_new0(qemu_irq, s->num_cs); 350929d1b52SPeter A. G. Crosthwaite for (i = 0; i < s->num_cs; ++i) { 3513efc10e1SAndreas Färber sysbus_init_irq(sbd, &s->cs_lines[i]); 352929d1b52SPeter A. G. Crosthwaite } 353929d1b52SPeter A. G. Crosthwaite 354*e87c93dfSPhilippe Mathieu-Daudé memory_region_init_io(&s->mmio, OBJECT(s), 355*e87c93dfSPhilippe Mathieu-Daudé &spi_ops[s->model_endianness == ENDIAN_MODE_BIG], s, 35629776739SPaolo Bonzini "xilinx-spi", R_MAX * 4); 3573efc10e1SAndreas Färber sysbus_init_mmio(sbd, &s->mmio); 358929d1b52SPeter A. G. Crosthwaite 359929d1b52SPeter A. G. Crosthwaite s->irqline = -1; 360929d1b52SPeter A. G. Crosthwaite 361929d1b52SPeter A. G. Crosthwaite fifo8_create(&s->tx_fifo, FIFO_CAPACITY); 362929d1b52SPeter A. G. Crosthwaite fifo8_create(&s->rx_fifo, FIFO_CAPACITY); 363929d1b52SPeter A. G. Crosthwaite } 364929d1b52SPeter A. G. Crosthwaite 365929d1b52SPeter A. G. Crosthwaite static const VMStateDescription vmstate_xilinx_spi = { 366929d1b52SPeter A. G. Crosthwaite .name = "xilinx_spi", 367929d1b52SPeter A. G. Crosthwaite .version_id = 1, 368929d1b52SPeter A. G. Crosthwaite .minimum_version_id = 1, 3690aa6c7dfSRichard Henderson .fields = (const VMStateField[]) { 370929d1b52SPeter A. G. Crosthwaite VMSTATE_FIFO8(tx_fifo, XilinxSPI), 371929d1b52SPeter A. G. Crosthwaite VMSTATE_FIFO8(rx_fifo, XilinxSPI), 372929d1b52SPeter A. G. Crosthwaite VMSTATE_UINT32_ARRAY(regs, XilinxSPI, R_MAX), 373929d1b52SPeter A. G. Crosthwaite VMSTATE_END_OF_LIST() 374929d1b52SPeter A. G. Crosthwaite } 375929d1b52SPeter A. G. Crosthwaite }; 376929d1b52SPeter A. G. Crosthwaite 377dc418eb2SRichard Henderson static const Property xilinx_spi_properties[] = { 378*e87c93dfSPhilippe Mathieu-Daudé DEFINE_PROP_ENDIAN_NODEFAULT("endianness", XilinxSPI, model_endianness), 379929d1b52SPeter A. G. Crosthwaite DEFINE_PROP_UINT8("num-ss-bits", XilinxSPI, num_cs, 1), 380929d1b52SPeter A. G. Crosthwaite }; 381929d1b52SPeter A. G. Crosthwaite 382929d1b52SPeter A. G. Crosthwaite static void xilinx_spi_class_init(ObjectClass *klass, void *data) 383929d1b52SPeter A. G. Crosthwaite { 384929d1b52SPeter A. G. Crosthwaite DeviceClass *dc = DEVICE_CLASS(klass); 385929d1b52SPeter A. G. Crosthwaite 386a7e1562cSPhilippe Mathieu-Daudé dc->realize = xilinx_spi_realize; 387e3d08143SPeter Maydell device_class_set_legacy_reset(dc, xlx_spi_reset); 3884f67d30bSMarc-André Lureau device_class_set_props(dc, xilinx_spi_properties); 389929d1b52SPeter A. G. Crosthwaite dc->vmsd = &vmstate_xilinx_spi; 390929d1b52SPeter A. G. Crosthwaite } 391929d1b52SPeter A. G. Crosthwaite 3928c43a6f0SAndreas Färber static const TypeInfo xilinx_spi_info = { 3933efc10e1SAndreas Färber .name = TYPE_XILINX_SPI, 394929d1b52SPeter A. G. Crosthwaite .parent = TYPE_SYS_BUS_DEVICE, 395929d1b52SPeter A. G. Crosthwaite .instance_size = sizeof(XilinxSPI), 396929d1b52SPeter A. G. Crosthwaite .class_init = xilinx_spi_class_init, 397929d1b52SPeter A. G. Crosthwaite }; 398929d1b52SPeter A. G. Crosthwaite 399929d1b52SPeter A. G. Crosthwaite static void xilinx_spi_register_types(void) 400929d1b52SPeter A. G. Crosthwaite { 401929d1b52SPeter A. G. Crosthwaite type_register_static(&xilinx_spi_info); 402929d1b52SPeter A. G. Crosthwaite } 403929d1b52SPeter A. G. Crosthwaite 404929d1b52SPeter A. G. Crosthwaite type_init(xilinx_spi_register_types) 405