| File: | hw/ssi/xilinx_spips.c |
| Location: | line 316, column 9 |
| Description: | Declared variable-length array (VLA) has zero size |
| 1 | /* | |||
| 2 | * QEMU model of the Xilinx Zynq SPI controller | |||
| 3 | * | |||
| 4 | * Copyright (c) 2012 Peter A. G. Crosthwaite | |||
| 5 | * | |||
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| 7 | * of this software and associated documentation files (the "Software"), to deal | |||
| 8 | * in the Software without restriction, including without limitation the rights | |||
| 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| 10 | * copies of the Software, and to permit persons to whom the Software is | |||
| 11 | * furnished to do so, subject to the following conditions: | |||
| 12 | * | |||
| 13 | * The above copyright notice and this permission notice shall be included in | |||
| 14 | * all copies or substantial portions of the Software. | |||
| 15 | * | |||
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
| 22 | * THE SOFTWARE. | |||
| 23 | */ | |||
| 24 | ||||
| 25 | #include "hw/sysbus.h" | |||
| 26 | #include "sysemu/sysemu.h" | |||
| 27 | #include "hw/ptimer.h" | |||
| 28 | #include "qemu/log.h" | |||
| 29 | #include "qemu/fifo8.h" | |||
| 30 | #include "hw/ssi.h" | |||
| 31 | #include "qemu/bitops.h" | |||
| 32 | ||||
| 33 | #ifndef XILINX_SPIPS_ERR_DEBUG0 | |||
| 34 | #define XILINX_SPIPS_ERR_DEBUG0 0 | |||
| 35 | #endif | |||
| 36 | ||||
| 37 | #define DB_PRINT_L(level, ...)do { if (0 > (level)) { fprintf(stderr, ": %s: ", __func__ ); fprintf(stderr, ...); } } while (0); do { \ | |||
| 38 | if (XILINX_SPIPS_ERR_DEBUG0 > (level)) { \ | |||
| 39 | fprintf(stderrstderr, ": %s: ", __func__); \ | |||
| 40 | fprintf(stderrstderr, ## __VA_ARGS__); \ | |||
| 41 | } \ | |||
| 42 | } while (0); | |||
| 43 | ||||
| 44 | /* config register */ | |||
| 45 | #define R_CONFIG(0x00 / 4) (0x00 / 4) | |||
| 46 | #define IFMODE(1 << 31) (1 << 31) | |||
| 47 | #define ENDIAN(1 << 26) (1 << 26) | |||
| 48 | #define MODEFAIL_GEN_EN(1 << 17) (1 << 17) | |||
| 49 | #define MAN_START_COM(1 << 16) (1 << 16) | |||
| 50 | #define MAN_START_EN(1 << 15) (1 << 15) | |||
| 51 | #define MANUAL_CS(1 << 14) (1 << 14) | |||
| 52 | #define CS(0xF << 10) (0xF << 10) | |||
| 53 | #define CS_SHIFT(10) (10) | |||
| 54 | #define PERI_SEL(1 << 9) (1 << 9) | |||
| 55 | #define REF_CLK(1 << 8) (1 << 8) | |||
| 56 | #define FIFO_WIDTH(3 << 6) (3 << 6) | |||
| 57 | #define BAUD_RATE_DIV(7 << 3) (7 << 3) | |||
| 58 | #define CLK_PH(1 << 2) (1 << 2) | |||
| 59 | #define CLK_POL(1 << 1) (1 << 1) | |||
| 60 | #define MODE_SEL(1 << 0) (1 << 0) | |||
| 61 | #define R_CONFIG_RSVD(0x7bf40000) (0x7bf40000) | |||
| 62 | ||||
| 63 | /* interrupt mechanism */ | |||
| 64 | #define R_INTR_STATUS(0x04 / 4) (0x04 / 4) | |||
| 65 | #define R_INTR_EN(0x08 / 4) (0x08 / 4) | |||
| 66 | #define R_INTR_DIS(0x0C / 4) (0x0C / 4) | |||
| 67 | #define R_INTR_MASK(0x10 / 4) (0x10 / 4) | |||
| 68 | #define IXR_TX_FIFO_UNDERFLOW(1 << 6) (1 << 6) | |||
| 69 | #define IXR_RX_FIFO_FULL(1 << 5) (1 << 5) | |||
| 70 | #define IXR_RX_FIFO_NOT_EMPTY(1 << 4) (1 << 4) | |||
| 71 | #define IXR_TX_FIFO_FULL(1 << 3) (1 << 3) | |||
| 72 | #define IXR_TX_FIFO_NOT_FULL(1 << 2) (1 << 2) | |||
| 73 | #define IXR_TX_FIFO_MODE_FAIL(1 << 1) (1 << 1) | |||
| 74 | #define IXR_RX_FIFO_OVERFLOW(1 << 0) (1 << 0) | |||
| 75 | #define IXR_ALL(((1 << 6)<<1)-1) ((IXR_TX_FIFO_UNDERFLOW(1 << 6)<<1)-1) | |||
| 76 | ||||
| 77 | #define R_EN(0x14 / 4) (0x14 / 4) | |||
| 78 | #define R_DELAY(0x18 / 4) (0x18 / 4) | |||
| 79 | #define R_TX_DATA(0x1C / 4) (0x1C / 4) | |||
| 80 | #define R_RX_DATA(0x20 / 4) (0x20 / 4) | |||
| 81 | #define R_SLAVE_IDLE_COUNT(0x24 / 4) (0x24 / 4) | |||
| 82 | #define R_TX_THRES(0x28 / 4) (0x28 / 4) | |||
| 83 | #define R_RX_THRES(0x2C / 4) (0x2C / 4) | |||
| 84 | #define R_TXD1(0x80 / 4) (0x80 / 4) | |||
| 85 | #define R_TXD2(0x84 / 4) (0x84 / 4) | |||
| 86 | #define R_TXD3(0x88 / 4) (0x88 / 4) | |||
| 87 | ||||
| 88 | #define R_LQSPI_CFG(0xa0 / 4) (0xa0 / 4) | |||
| 89 | #define R_LQSPI_CFG_RESET0x03A002EB 0x03A002EB | |||
| 90 | #define LQSPI_CFG_LQ_MODE(1 << 31) (1 << 31) | |||
| 91 | #define LQSPI_CFG_TWO_MEM(1 << 30) (1 << 30) | |||
| 92 | #define LQSPI_CFG_SEP_BUS(1 << 30) (1 << 30) | |||
| 93 | #define LQSPI_CFG_U_PAGE(1 << 28) (1 << 28) | |||
| 94 | #define LQSPI_CFG_MODE_EN(1 << 25) (1 << 25) | |||
| 95 | #define LQSPI_CFG_MODE_WIDTH8 8 | |||
| 96 | #define LQSPI_CFG_MODE_SHIFT16 16 | |||
| 97 | #define LQSPI_CFG_DUMMY_WIDTH3 3 | |||
| 98 | #define LQSPI_CFG_DUMMY_SHIFT8 8 | |||
| 99 | #define LQSPI_CFG_INST_CODE0xFF 0xFF | |||
| 100 | ||||
| 101 | #define R_LQSPI_STS(0xA4 / 4) (0xA4 / 4) | |||
| 102 | #define LQSPI_STS_WR_RECVD(1 << 1) (1 << 1) | |||
| 103 | ||||
| 104 | #define R_MOD_ID(0xFC / 4) (0xFC / 4) | |||
| 105 | ||||
| 106 | #define R_MAX((0xFC / 4)+1) (R_MOD_ID(0xFC / 4)+1) | |||
| 107 | ||||
| 108 | /* size of TXRX FIFOs */ | |||
| 109 | #define RXFF_A32 32 | |||
| 110 | #define TXFF_A32 32 | |||
| 111 | ||||
| 112 | #define RXFF_A_Q(64 * 4) (64 * 4) | |||
| 113 | #define TXFF_A_Q(64 * 4) (64 * 4) | |||
| 114 | ||||
| 115 | /* 16MB per linear region */ | |||
| 116 | #define LQSPI_ADDRESS_BITS24 24 | |||
| 117 | /* Bite off 4k chunks at a time */ | |||
| 118 | #define LQSPI_CACHE_SIZE1024 1024 | |||
| 119 | ||||
| 120 | #define SNOOP_CHECKING0xFF 0xFF | |||
| 121 | #define SNOOP_NONE0xFE 0xFE | |||
| 122 | #define SNOOP_STRIPING0 0 | |||
| 123 | ||||
| 124 | typedef enum { | |||
| 125 | READ = 0x3, | |||
| 126 | FAST_READ = 0xb, | |||
| 127 | DOR = 0x3b, | |||
| 128 | QOR = 0x6b, | |||
| 129 | DIOR = 0xbb, | |||
| 130 | QIOR = 0xeb, | |||
| 131 | ||||
| 132 | PP = 0x2, | |||
| 133 | DPP = 0xa2, | |||
| 134 | QPP = 0x32, | |||
| 135 | } FlashCMD; | |||
| 136 | ||||
| 137 | typedef struct { | |||
| 138 | SysBusDevice parent_obj; | |||
| 139 | ||||
| 140 | MemoryRegion iomem; | |||
| 141 | MemoryRegion mmlqspi; | |||
| 142 | ||||
| 143 | qemu_irq irq; | |||
| 144 | int irqline; | |||
| 145 | ||||
| 146 | uint8_t num_cs; | |||
| 147 | uint8_t num_busses; | |||
| 148 | ||||
| 149 | uint8_t snoop_state; | |||
| 150 | qemu_irq *cs_lines; | |||
| 151 | SSIBus **spi; | |||
| 152 | ||||
| 153 | Fifo8 rx_fifo; | |||
| 154 | Fifo8 tx_fifo; | |||
| 155 | ||||
| 156 | uint8_t num_txrx_bytes; | |||
| 157 | ||||
| 158 | uint32_t regs[R_MAX((0xFC / 4)+1)]; | |||
| 159 | } XilinxSPIPS; | |||
| 160 | ||||
| 161 | typedef struct { | |||
| 162 | XilinxSPIPS parent_obj; | |||
| 163 | ||||
| 164 | uint8_t lqspi_buf[LQSPI_CACHE_SIZE1024]; | |||
| 165 | hwaddr lqspi_cached_addr; | |||
| 166 | } XilinxQSPIPS; | |||
| 167 | ||||
| 168 | typedef struct XilinxSPIPSClass { | |||
| 169 | SysBusDeviceClass parent_class; | |||
| 170 | ||||
| 171 | const MemoryRegionOps *reg_ops; | |||
| 172 | ||||
| 173 | uint32_t rx_fifo_size; | |||
| 174 | uint32_t tx_fifo_size; | |||
| 175 | } XilinxSPIPSClass; | |||
| 176 | ||||
| 177 | #define TYPE_XILINX_SPIPS"xlnx.ps7-spi" "xlnx.ps7-spi" | |||
| 178 | #define TYPE_XILINX_QSPIPS"xlnx.ps7-qspi" "xlnx.ps7-qspi" | |||
| 179 | ||||
| 180 | #define XILINX_SPIPS(obj)((XilinxSPIPS *)object_dynamic_cast_assert(((Object *)((obj)) ), ("xlnx.ps7-spi"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 180, __func__)) \ | |||
| 181 | OBJECT_CHECK(XilinxSPIPS, (obj), TYPE_XILINX_SPIPS)((XilinxSPIPS *)object_dynamic_cast_assert(((Object *)((obj)) ), ("xlnx.ps7-spi"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 181, __func__)) | |||
| 182 | #define XILINX_SPIPS_CLASS(klass)((XilinxSPIPSClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("xlnx.ps7-spi"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 182, __func__)) \ | |||
| 183 | OBJECT_CLASS_CHECK(XilinxSPIPSClass, (klass), TYPE_XILINX_SPIPS)((XilinxSPIPSClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("xlnx.ps7-spi"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 183, __func__)) | |||
| 184 | #define XILINX_SPIPS_GET_CLASS(obj)((XilinxSPIPSClass *)object_class_dynamic_cast_assert(((ObjectClass *)(object_get_class(((Object *)((obj)))))), ("xlnx.ps7-spi") , "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 184, __func__)) \ | |||
| 185 | OBJECT_GET_CLASS(XilinxSPIPSClass, (obj), TYPE_XILINX_SPIPS)((XilinxSPIPSClass *)object_class_dynamic_cast_assert(((ObjectClass *)(object_get_class(((Object *)((obj)))))), ("xlnx.ps7-spi") , "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 185, __func__)) | |||
| 186 | ||||
| 187 | #define XILINX_QSPIPS(obj)((XilinxQSPIPS *)object_dynamic_cast_assert(((Object *)((obj) )), ("xlnx.ps7-qspi"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 187, __func__)) \ | |||
| 188 | OBJECT_CHECK(XilinxQSPIPS, (obj), TYPE_XILINX_QSPIPS)((XilinxQSPIPS *)object_dynamic_cast_assert(((Object *)((obj) )), ("xlnx.ps7-qspi"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 188, __func__)) | |||
| 189 | ||||
| 190 | static inline int num_effective_busses(XilinxSPIPS *s) | |||
| 191 | { | |||
| 192 | return (s->regs[R_LQSPI_CFG(0xa0 / 4)] & LQSPI_CFG_SEP_BUS(1 << 30) && | |||
| 193 | s->regs[R_LQSPI_CFG(0xa0 / 4)] & LQSPI_CFG_TWO_MEM(1 << 30)) ? s->num_busses : 1; | |||
| 194 | } | |||
| 195 | ||||
| 196 | static inline bool_Bool xilinx_spips_cs_is_set(XilinxSPIPS *s, int i, int field) | |||
| 197 | { | |||
| 198 | return ~field & (1 << i) && (s->regs[R_CONFIG(0x00 / 4)] & MANUAL_CS(1 << 14) | |||
| 199 | || !fifo8_is_empty(&s->tx_fifo)); | |||
| 200 | } | |||
| 201 | ||||
| 202 | static void xilinx_spips_update_cs_lines(XilinxSPIPS *s) | |||
| 203 | { | |||
| 204 | int i, j; | |||
| 205 | bool_Bool found = false0; | |||
| 206 | int field = s->regs[R_CONFIG(0x00 / 4)] >> CS_SHIFT(10); | |||
| 207 | ||||
| 208 | for (i = 0; i < s->num_cs; i++) { | |||
| 209 | for (j = 0; j < num_effective_busses(s); j++) { | |||
| 210 | int upage = !!(s->regs[R_LQSPI_STS(0xA4 / 4)] & LQSPI_CFG_U_PAGE(1 << 28)); | |||
| 211 | int cs_to_set = (j * s->num_cs + i + upage) % | |||
| 212 | (s->num_cs * s->num_busses); | |||
| 213 | ||||
| 214 | if (xilinx_spips_cs_is_set(s, i, field) && !found) { | |||
| 215 | DB_PRINT_L(0, "selecting slave %d\n", i)do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "selecting slave %d\n", i); } } while (0);; | |||
| 216 | qemu_set_irq(s->cs_lines[cs_to_set], 0); | |||
| 217 | } else { | |||
| 218 | DB_PRINT_L(0, "deselecting slave %d\n", i)do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "deselecting slave %d\n", i); } } while (0);; | |||
| 219 | qemu_set_irq(s->cs_lines[cs_to_set], 1); | |||
| 220 | } | |||
| 221 | } | |||
| 222 | if (xilinx_spips_cs_is_set(s, i, field)) { | |||
| 223 | found = true1; | |||
| 224 | } | |||
| 225 | } | |||
| 226 | if (!found) { | |||
| 227 | s->snoop_state = SNOOP_CHECKING0xFF; | |||
| 228 | DB_PRINT_L(1, "moving to snoop check state\n")do { if (0 > (1)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "moving to snoop check state\n"); } } while (0);; | |||
| 229 | } | |||
| 230 | } | |||
| 231 | ||||
| 232 | static void xilinx_spips_update_ixr(XilinxSPIPS *s) | |||
| 233 | { | |||
| 234 | if (s->regs[R_LQSPI_CFG(0xa0 / 4)] & LQSPI_CFG_LQ_MODE(1 << 31)) { | |||
| 235 | return; | |||
| 236 | } | |||
| 237 | /* These are set/cleared as they occur */ | |||
| 238 | s->regs[R_INTR_STATUS(0x04 / 4)] &= (IXR_TX_FIFO_UNDERFLOW(1 << 6) | IXR_RX_FIFO_OVERFLOW(1 << 0) | | |||
| 239 | IXR_TX_FIFO_MODE_FAIL(1 << 1)); | |||
| 240 | /* these are pure functions of fifo state, set them here */ | |||
| 241 | s->regs[R_INTR_STATUS(0x04 / 4)] |= | |||
| 242 | (fifo8_is_full(&s->rx_fifo) ? IXR_RX_FIFO_FULL(1 << 5) : 0) | | |||
| 243 | (s->rx_fifo.num >= s->regs[R_RX_THRES(0x2C / 4)] ? IXR_RX_FIFO_NOT_EMPTY(1 << 4) : 0) | | |||
| 244 | (fifo8_is_full(&s->tx_fifo) ? IXR_TX_FIFO_FULL(1 << 3) : 0) | | |||
| 245 | (s->tx_fifo.num < s->regs[R_TX_THRES(0x28 / 4)] ? IXR_TX_FIFO_NOT_FULL(1 << 2) : 0); | |||
| 246 | /* drive external interrupt pin */ | |||
| 247 | int new_irqline = !!(s->regs[R_INTR_MASK(0x10 / 4)] & s->regs[R_INTR_STATUS(0x04 / 4)] & | |||
| 248 | IXR_ALL(((1 << 6)<<1)-1)); | |||
| 249 | if (new_irqline != s->irqline) { | |||
| 250 | s->irqline = new_irqline; | |||
| 251 | qemu_set_irq(s->irq, s->irqline); | |||
| 252 | } | |||
| 253 | } | |||
| 254 | ||||
| 255 | static void xilinx_spips_reset(DeviceState *d) | |||
| 256 | { | |||
| 257 | XilinxSPIPS *s = XILINX_SPIPS(d)((XilinxSPIPS *)object_dynamic_cast_assert(((Object *)((d))), ("xlnx.ps7-spi"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 257, __func__)); | |||
| 258 | ||||
| 259 | int i; | |||
| 260 | for (i = 0; i < R_MAX((0xFC / 4)+1); i++) { | |||
| 261 | s->regs[i] = 0; | |||
| 262 | } | |||
| 263 | ||||
| 264 | fifo8_reset(&s->rx_fifo); | |||
| 265 | fifo8_reset(&s->rx_fifo); | |||
| 266 | /* non zero resets */ | |||
| 267 | s->regs[R_CONFIG(0x00 / 4)] |= MODEFAIL_GEN_EN(1 << 17); | |||
| 268 | s->regs[R_SLAVE_IDLE_COUNT(0x24 / 4)] = 0xFF; | |||
| 269 | s->regs[R_TX_THRES(0x28 / 4)] = 1; | |||
| 270 | s->regs[R_RX_THRES(0x2C / 4)] = 1; | |||
| 271 | /* FIXME: move magic number definition somewhere sensible */ | |||
| 272 | s->regs[R_MOD_ID(0xFC / 4)] = 0x01090106; | |||
| 273 | s->regs[R_LQSPI_CFG(0xa0 / 4)] = R_LQSPI_CFG_RESET0x03A002EB; | |||
| 274 | s->snoop_state = SNOOP_CHECKING0xFF; | |||
| 275 | xilinx_spips_update_ixr(s); | |||
| 276 | xilinx_spips_update_cs_lines(s); | |||
| 277 | } | |||
| 278 | ||||
| 279 | /* N way (num) in place bit striper. Lay out row wise bits (LSB to MSB) | |||
| 280 | * column wise (from element 0 to N-1). num is the length of x, and dir | |||
| 281 | * reverses the direction of the transform. Best illustrated by example: | |||
| 282 | * Each digit in the below array is a single bit (num == 3): | |||
| 283 | * | |||
| 284 | * {{ 76543210, } ----- stripe (dir == false) -----> {{ FCheb630, } | |||
| 285 | * { hgfedcba, } { GDAfc741, } | |||
| 286 | * { HGFEDCBA, }} <---- upstripe (dir == true) ----- { HEBgda52, }} | |||
| 287 | */ | |||
| 288 | ||||
| 289 | static inline void stripe8(uint8_t *x, int num, bool_Bool dir) | |||
| 290 | { | |||
| 291 | uint8_t r[num]; | |||
| 292 | memset(r, 0, sizeof(uint8_t) * num); | |||
| 293 | int idx[2] = {0, 0}; | |||
| 294 | int bit[2] = {0, 0}; | |||
| 295 | int d = dir; | |||
| 296 | ||||
| 297 | for (idx[0] = 0; idx[0] < num; ++idx[0]) { | |||
| 298 | for (bit[0] = 0; bit[0] < 8; ++bit[0]) { | |||
| 299 | r[idx[d]] |= x[idx[!d]] & 1 << bit[!d] ? 1 << bit[d] : 0; | |||
| 300 | idx[1] = (idx[1] + 1) % num; | |||
| 301 | if (!idx[1]) { | |||
| 302 | bit[1]++; | |||
| 303 | } | |||
| 304 | } | |||
| 305 | } | |||
| 306 | memcpy(x, r, sizeof(uint8_t) * num); | |||
| 307 | } | |||
| 308 | ||||
| 309 | static void xilinx_spips_flush_txfifo(XilinxSPIPS *s) | |||
| 310 | { | |||
| 311 | int debug_level = 0; | |||
| 312 | ||||
| 313 | for (;;) { | |||
| ||||
| 314 | int i; | |||
| 315 | uint8_t tx = 0; | |||
| 316 | uint8_t tx_rx[num_effective_busses(s)]; | |||
| ||||
| 317 | ||||
| 318 | if (fifo8_is_empty(&s->tx_fifo)) { | |||
| 319 | if (!(s->regs[R_LQSPI_CFG(0xa0 / 4)] & LQSPI_CFG_LQ_MODE(1 << 31))) { | |||
| 320 | s->regs[R_INTR_STATUS(0x04 / 4)] |= IXR_TX_FIFO_UNDERFLOW(1 << 6); | |||
| 321 | } | |||
| 322 | xilinx_spips_update_ixr(s); | |||
| 323 | return; | |||
| 324 | } else if (s->snoop_state == SNOOP_STRIPING0) { | |||
| 325 | for (i = 0; i < num_effective_busses(s); ++i) { | |||
| 326 | tx_rx[i] = fifo8_pop(&s->tx_fifo); | |||
| 327 | } | |||
| 328 | stripe8(tx_rx, num_effective_busses(s), false0); | |||
| 329 | } else { | |||
| 330 | tx = fifo8_pop(&s->tx_fifo); | |||
| 331 | for (i = 0; i < num_effective_busses(s); ++i) { | |||
| 332 | tx_rx[i] = tx; | |||
| 333 | } | |||
| 334 | } | |||
| 335 | ||||
| 336 | for (i = 0; i < num_effective_busses(s); ++i) { | |||
| 337 | DB_PRINT_L(debug_level, "tx = %02x\n", tx_rx[i])do { if (0 > (debug_level)) { fprintf(stderr, ": %s: ", __func__ ); fprintf(stderr, "tx = %02x\n", tx_rx[i]); } } while (0);; | |||
| 338 | tx_rx[i] = ssi_transfer(s->spi[i], (uint32_t)tx_rx[i]); | |||
| 339 | DB_PRINT_L(debug_level, "rx = %02x\n", tx_rx[i])do { if (0 > (debug_level)) { fprintf(stderr, ": %s: ", __func__ ); fprintf(stderr, "rx = %02x\n", tx_rx[i]); } } while (0);; | |||
| 340 | } | |||
| 341 | ||||
| 342 | if (fifo8_is_full(&s->rx_fifo)) { | |||
| 343 | s->regs[R_INTR_STATUS(0x04 / 4)] |= IXR_RX_FIFO_OVERFLOW(1 << 0); | |||
| 344 | DB_PRINT_L(0, "rx FIFO overflow")do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "rx FIFO overflow"); } } while (0);; | |||
| 345 | } else if (s->snoop_state == SNOOP_STRIPING0) { | |||
| 346 | stripe8(tx_rx, num_effective_busses(s), true1); | |||
| 347 | for (i = 0; i < num_effective_busses(s); ++i) { | |||
| 348 | fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[i]); | |||
| 349 | } | |||
| 350 | } else { | |||
| 351 | fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[0]); | |||
| 352 | } | |||
| 353 | ||||
| 354 | DB_PRINT_L(debug_level, "initial snoop state: %x\n",do { if (0 > (debug_level)) { fprintf(stderr, ": %s: ", __func__ ); fprintf(stderr, "initial snoop state: %x\n", (unsigned)s-> snoop_state); } } while (0); | |||
| 355 | (unsigned)s->snoop_state)do { if (0 > (debug_level)) { fprintf(stderr, ": %s: ", __func__ ); fprintf(stderr, "initial snoop state: %x\n", (unsigned)s-> snoop_state); } } while (0);; | |||
| 356 | switch (s->snoop_state) { | |||
| 357 | case (SNOOP_CHECKING0xFF): | |||
| 358 | switch (tx) { /* new instruction code */ | |||
| 359 | case READ: /* 3 address bytes, no dummy bytes/cycles */ | |||
| 360 | case PP: | |||
| 361 | case DPP: | |||
| 362 | case QPP: | |||
| 363 | s->snoop_state = 3; | |||
| 364 | break; | |||
| 365 | case FAST_READ: /* 3 address bytes, 1 dummy byte */ | |||
| 366 | case DOR: | |||
| 367 | case QOR: | |||
| 368 | case DIOR: /* FIXME: these vary between vendor - set to spansion */ | |||
| 369 | s->snoop_state = 4; | |||
| 370 | break; | |||
| 371 | case QIOR: /* 3 address bytes, 2 dummy bytes */ | |||
| 372 | s->snoop_state = 6; | |||
| 373 | break; | |||
| 374 | default: | |||
| 375 | s->snoop_state = SNOOP_NONE0xFE; | |||
| 376 | } | |||
| 377 | break; | |||
| 378 | case (SNOOP_STRIPING0): | |||
| 379 | case (SNOOP_NONE0xFE): | |||
| 380 | /* Once we hit the boring stuff - squelch debug noise */ | |||
| 381 | if (!debug_level) { | |||
| 382 | DB_PRINT_L(0, "squelching debug info ....\n")do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "squelching debug info ....\n"); } } while (0);; | |||
| 383 | debug_level = 1; | |||
| 384 | } | |||
| 385 | break; | |||
| 386 | default: | |||
| 387 | s->snoop_state--; | |||
| 388 | } | |||
| 389 | DB_PRINT_L(debug_level, "final snoop state: %x\n",do { if (0 > (debug_level)) { fprintf(stderr, ": %s: ", __func__ ); fprintf(stderr, "final snoop state: %x\n", (unsigned)s-> snoop_state); } } while (0); | |||
| 390 | (unsigned)s->snoop_state)do { if (0 > (debug_level)) { fprintf(stderr, ": %s: ", __func__ ); fprintf(stderr, "final snoop state: %x\n", (unsigned)s-> snoop_state); } } while (0);; | |||
| 391 | } | |||
| 392 | } | |||
| 393 | ||||
| 394 | static inline void rx_data_bytes(XilinxSPIPS *s, uint8_t *value, int max) | |||
| 395 | { | |||
| 396 | int i; | |||
| 397 | ||||
| 398 | for (i = 0; i < max && !fifo8_is_empty(&s->rx_fifo); ++i) { | |||
| 399 | value[i] = fifo8_pop(&s->rx_fifo); | |||
| 400 | } | |||
| 401 | } | |||
| 402 | ||||
| 403 | static uint64_t xilinx_spips_read(void *opaque, hwaddr addr, | |||
| 404 | unsigned size) | |||
| 405 | { | |||
| 406 | XilinxSPIPS *s = opaque; | |||
| 407 | uint32_t mask = ~0; | |||
| 408 | uint32_t ret; | |||
| 409 | uint8_t rx_buf[4]; | |||
| 410 | ||||
| 411 | addr >>= 2; | |||
| 412 | switch (addr) { | |||
| 413 | case R_CONFIG(0x00 / 4): | |||
| 414 | mask = ~(R_CONFIG_RSVD(0x7bf40000) | MAN_START_COM(1 << 16)); | |||
| 415 | break; | |||
| 416 | case R_INTR_STATUS(0x04 / 4): | |||
| 417 | ret = s->regs[addr] & IXR_ALL(((1 << 6)<<1)-1); | |||
| 418 | s->regs[addr] = 0; | |||
| 419 | DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret)do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "addr=" "%016" "l" "x" " = %x\n", addr * 4, ret); } } while (0);; | |||
| 420 | return ret; | |||
| 421 | case R_INTR_MASK(0x10 / 4): | |||
| 422 | mask = IXR_ALL(((1 << 6)<<1)-1); | |||
| 423 | break; | |||
| 424 | case R_EN(0x14 / 4): | |||
| 425 | mask = 0x1; | |||
| 426 | break; | |||
| 427 | case R_SLAVE_IDLE_COUNT(0x24 / 4): | |||
| 428 | mask = 0xFF; | |||
| 429 | break; | |||
| 430 | case R_MOD_ID(0xFC / 4): | |||
| 431 | mask = 0x01FFFFFF; | |||
| 432 | break; | |||
| 433 | case R_INTR_EN(0x08 / 4): | |||
| 434 | case R_INTR_DIS(0x0C / 4): | |||
| 435 | case R_TX_DATA(0x1C / 4): | |||
| 436 | mask = 0; | |||
| 437 | break; | |||
| 438 | case R_RX_DATA(0x20 / 4): | |||
| 439 | memset(rx_buf, 0, sizeof(rx_buf)); | |||
| 440 | rx_data_bytes(s, rx_buf, s->num_txrx_bytes); | |||
| 441 | ret = s->regs[R_CONFIG(0x00 / 4)] & ENDIAN(1 << 26) ? cpu_to_be32(*(uint32_t *)rx_buf) | |||
| 442 | : cpu_to_le32(*(uint32_t *)rx_buf); | |||
| 443 | DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret)do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "addr=" "%016" "l" "x" " = %x\n", addr * 4, ret); } } while (0);; | |||
| 444 | xilinx_spips_update_ixr(s); | |||
| 445 | return ret; | |||
| 446 | } | |||
| 447 | DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4,do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "addr=" "%016" "l" "x" " = %x\n", addr * 4, s->regs [addr] & mask); } } while (0); | |||
| 448 | s->regs[addr] & mask)do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "addr=" "%016" "l" "x" " = %x\n", addr * 4, s->regs [addr] & mask); } } while (0);; | |||
| 449 | return s->regs[addr] & mask; | |||
| 450 | ||||
| 451 | } | |||
| 452 | ||||
| 453 | static inline void tx_data_bytes(XilinxSPIPS *s, uint32_t value, int num) | |||
| 454 | { | |||
| 455 | int i; | |||
| 456 | for (i = 0; i < num && !fifo8_is_full(&s->tx_fifo); ++i) { | |||
| 457 | if (s->regs[R_CONFIG(0x00 / 4)] & ENDIAN(1 << 26)) { | |||
| 458 | fifo8_push(&s->tx_fifo, (uint8_t)(value >> 24)); | |||
| 459 | value <<= 8; | |||
| 460 | } else { | |||
| 461 | fifo8_push(&s->tx_fifo, (uint8_t)value); | |||
| 462 | value >>= 8; | |||
| 463 | } | |||
| 464 | } | |||
| 465 | } | |||
| 466 | ||||
| 467 | static void xilinx_spips_write(void *opaque, hwaddr addr, | |||
| 468 | uint64_t value, unsigned size) | |||
| 469 | { | |||
| 470 | int mask = ~0; | |||
| 471 | int man_start_com = 0; | |||
| 472 | XilinxSPIPS *s = opaque; | |||
| 473 | ||||
| 474 | DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value)do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "addr=" "%016" "l" "x" " = %x\n", addr, (unsigned)value ); } } while (0);; | |||
| 475 | addr >>= 2; | |||
| 476 | switch (addr) { | |||
| 477 | case R_CONFIG(0x00 / 4): | |||
| 478 | mask = ~(R_CONFIG_RSVD(0x7bf40000) | MAN_START_COM(1 << 16)); | |||
| 479 | if (value & MAN_START_COM(1 << 16)) { | |||
| 480 | man_start_com = 1; | |||
| 481 | } | |||
| 482 | break; | |||
| 483 | case R_INTR_STATUS(0x04 / 4): | |||
| 484 | mask = IXR_ALL(((1 << 6)<<1)-1); | |||
| 485 | s->regs[R_INTR_STATUS(0x04 / 4)] &= ~(mask & value); | |||
| 486 | goto no_reg_update; | |||
| 487 | case R_INTR_DIS(0x0C / 4): | |||
| 488 | mask = IXR_ALL(((1 << 6)<<1)-1); | |||
| 489 | s->regs[R_INTR_MASK(0x10 / 4)] &= ~(mask & value); | |||
| 490 | goto no_reg_update; | |||
| 491 | case R_INTR_EN(0x08 / 4): | |||
| 492 | mask = IXR_ALL(((1 << 6)<<1)-1); | |||
| 493 | s->regs[R_INTR_MASK(0x10 / 4)] |= mask & value; | |||
| 494 | goto no_reg_update; | |||
| 495 | case R_EN(0x14 / 4): | |||
| 496 | mask = 0x1; | |||
| 497 | break; | |||
| 498 | case R_SLAVE_IDLE_COUNT(0x24 / 4): | |||
| 499 | mask = 0xFF; | |||
| 500 | break; | |||
| 501 | case R_RX_DATA(0x20 / 4): | |||
| 502 | case R_INTR_MASK(0x10 / 4): | |||
| 503 | case R_MOD_ID(0xFC / 4): | |||
| 504 | mask = 0; | |||
| 505 | break; | |||
| 506 | case R_TX_DATA(0x1C / 4): | |||
| 507 | tx_data_bytes(s, (uint32_t)value, s->num_txrx_bytes); | |||
| 508 | goto no_reg_update; | |||
| 509 | case R_TXD1(0x80 / 4): | |||
| 510 | tx_data_bytes(s, (uint32_t)value, 1); | |||
| 511 | goto no_reg_update; | |||
| 512 | case R_TXD2(0x84 / 4): | |||
| 513 | tx_data_bytes(s, (uint32_t)value, 2); | |||
| 514 | goto no_reg_update; | |||
| 515 | case R_TXD3(0x88 / 4): | |||
| 516 | tx_data_bytes(s, (uint32_t)value, 3); | |||
| 517 | goto no_reg_update; | |||
| 518 | } | |||
| 519 | s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask); | |||
| 520 | no_reg_update: | |||
| 521 | xilinx_spips_update_cs_lines(s); | |||
| 522 | if ((man_start_com && s->regs[R_CONFIG(0x00 / 4)] & MAN_START_EN(1 << 15)) || | |||
| 523 | (fifo8_is_empty(&s->tx_fifo) && s->regs[R_CONFIG(0x00 / 4)] & MAN_START_EN(1 << 15))) { | |||
| 524 | xilinx_spips_flush_txfifo(s); | |||
| 525 | } | |||
| 526 | xilinx_spips_update_cs_lines(s); | |||
| 527 | xilinx_spips_update_ixr(s); | |||
| 528 | } | |||
| 529 | ||||
| 530 | static const MemoryRegionOps spips_ops = { | |||
| 531 | .read = xilinx_spips_read, | |||
| 532 | .write = xilinx_spips_write, | |||
| 533 | .endianness = DEVICE_LITTLE_ENDIAN, | |||
| 534 | }; | |||
| 535 | ||||
| 536 | static void xilinx_qspips_write(void *opaque, hwaddr addr, | |||
| 537 | uint64_t value, unsigned size) | |||
| 538 | { | |||
| 539 | XilinxQSPIPS *q = XILINX_QSPIPS(opaque)((XilinxQSPIPS *)object_dynamic_cast_assert(((Object *)((opaque ))), ("xlnx.ps7-qspi"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 539, __func__)); | |||
| 540 | ||||
| 541 | xilinx_spips_write(opaque, addr, value, size); | |||
| 542 | addr >>= 2; | |||
| 543 | ||||
| 544 | if (addr == R_LQSPI_CFG(0xa0 / 4)) { | |||
| 545 | q->lqspi_cached_addr = ~0ULL; | |||
| 546 | } | |||
| 547 | } | |||
| 548 | ||||
| 549 | static const MemoryRegionOps qspips_ops = { | |||
| 550 | .read = xilinx_spips_read, | |||
| 551 | .write = xilinx_qspips_write, | |||
| 552 | .endianness = DEVICE_LITTLE_ENDIAN, | |||
| 553 | }; | |||
| 554 | ||||
| 555 | #define LQSPI_CACHE_SIZE1024 1024 | |||
| 556 | ||||
| 557 | static uint64_t | |||
| 558 | lqspi_read(void *opaque, hwaddr addr, unsigned int size) | |||
| 559 | { | |||
| 560 | int i; | |||
| 561 | XilinxQSPIPS *q = opaque; | |||
| 562 | XilinxSPIPS *s = opaque; | |||
| 563 | uint32_t ret; | |||
| 564 | ||||
| 565 | if (addr >= q->lqspi_cached_addr && | |||
| 566 | addr <= q->lqspi_cached_addr + LQSPI_CACHE_SIZE1024 - 4) { | |||
| 567 | uint8_t *retp = &q->lqspi_buf[addr - q->lqspi_cached_addr]; | |||
| 568 | ret = cpu_to_le32(*(uint32_t *)retp); | |||
| 569 | DB_PRINT_L(1, "addr: %08x, data: %08x\n", (unsigned)addr,do { if (0 > (1)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "addr: %08x, data: %08x\n", (unsigned)addr, (unsigned )ret); } } while (0); | |||
| 570 | (unsigned)ret)do { if (0 > (1)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "addr: %08x, data: %08x\n", (unsigned)addr, (unsigned )ret); } } while (0);; | |||
| 571 | return ret; | |||
| 572 | } else { | |||
| 573 | int flash_addr = (addr / num_effective_busses(s)); | |||
| 574 | int slave = flash_addr >> LQSPI_ADDRESS_BITS24; | |||
| 575 | int cache_entry = 0; | |||
| 576 | uint32_t u_page_save = s->regs[R_LQSPI_STS(0xA4 / 4)] & ~LQSPI_CFG_U_PAGE(1 << 28); | |||
| 577 | ||||
| 578 | s->regs[R_LQSPI_STS(0xA4 / 4)] &= ~LQSPI_CFG_U_PAGE(1 << 28); | |||
| 579 | s->regs[R_LQSPI_STS(0xA4 / 4)] |= slave ? LQSPI_CFG_U_PAGE(1 << 28) : 0; | |||
| 580 | ||||
| 581 | DB_PRINT_L(0, "config reg status: %08x\n", s->regs[R_LQSPI_CFG])do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "config reg status: %08x\n", s->regs[(0xa0 / 4)]) ; } } while (0);; | |||
| 582 | ||||
| 583 | fifo8_reset(&s->tx_fifo); | |||
| 584 | fifo8_reset(&s->rx_fifo); | |||
| 585 | ||||
| 586 | /* instruction */ | |||
| 587 | DB_PRINT_L(0, "pushing read instruction: %02x\n",do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "pushing read instruction: %02x\n", (unsigned)(uint8_t )(s->regs[(0xa0 / 4)] & 0xFF)); } } while (0); | |||
| 588 | (unsigned)(uint8_t)(s->regs[R_LQSPI_CFG] &do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "pushing read instruction: %02x\n", (unsigned)(uint8_t )(s->regs[(0xa0 / 4)] & 0xFF)); } } while (0); | |||
| 589 | LQSPI_CFG_INST_CODE))do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "pushing read instruction: %02x\n", (unsigned)(uint8_t )(s->regs[(0xa0 / 4)] & 0xFF)); } } while (0);; | |||
| 590 | fifo8_push(&s->tx_fifo, s->regs[R_LQSPI_CFG(0xa0 / 4)] & LQSPI_CFG_INST_CODE0xFF); | |||
| 591 | /* read address */ | |||
| 592 | DB_PRINT_L(0, "pushing read address %06x\n", flash_addr)do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "pushing read address %06x\n", flash_addr); } } while (0);; | |||
| 593 | fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 16)); | |||
| 594 | fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 8)); | |||
| 595 | fifo8_push(&s->tx_fifo, (uint8_t)flash_addr); | |||
| 596 | /* mode bits */ | |||
| 597 | if (s->regs[R_LQSPI_CFG(0xa0 / 4)] & LQSPI_CFG_MODE_EN(1 << 25)) { | |||
| 598 | fifo8_push(&s->tx_fifo, extract32(s->regs[R_LQSPI_CFG(0xa0 / 4)], | |||
| 599 | LQSPI_CFG_MODE_SHIFT16, | |||
| 600 | LQSPI_CFG_MODE_WIDTH8)); | |||
| 601 | } | |||
| 602 | /* dummy bytes */ | |||
| 603 | for (i = 0; i < (extract32(s->regs[R_LQSPI_CFG(0xa0 / 4)], LQSPI_CFG_DUMMY_SHIFT8, | |||
| 604 | LQSPI_CFG_DUMMY_WIDTH3)); ++i) { | |||
| 605 | DB_PRINT_L(0, "pushing dummy byte\n")do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "pushing dummy byte\n"); } } while (0);; | |||
| 606 | fifo8_push(&s->tx_fifo, 0); | |||
| 607 | } | |||
| 608 | xilinx_spips_update_cs_lines(s); | |||
| 609 | xilinx_spips_flush_txfifo(s); | |||
| 610 | fifo8_reset(&s->rx_fifo); | |||
| 611 | ||||
| 612 | DB_PRINT_L(0, "starting QSPI data read\n")do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "starting QSPI data read\n"); } } while (0);; | |||
| 613 | ||||
| 614 | while (cache_entry < LQSPI_CACHE_SIZE1024) { | |||
| 615 | for (i = 0; i < 64; ++i) { | |||
| 616 | tx_data_bytes(s, 0, 1); | |||
| 617 | } | |||
| 618 | xilinx_spips_flush_txfifo(s); | |||
| 619 | for (i = 0; i < 64; ++i) { | |||
| 620 | rx_data_bytes(s, &q->lqspi_buf[cache_entry++], 1); | |||
| 621 | } | |||
| 622 | } | |||
| 623 | ||||
| 624 | s->regs[R_LQSPI_STS(0xA4 / 4)] &= ~LQSPI_CFG_U_PAGE(1 << 28); | |||
| 625 | s->regs[R_LQSPI_STS(0xA4 / 4)] |= u_page_save; | |||
| 626 | xilinx_spips_update_cs_lines(s); | |||
| 627 | ||||
| 628 | q->lqspi_cached_addr = flash_addr * num_effective_busses(s); | |||
| 629 | return lqspi_read(opaque, addr, size); | |||
| 630 | } | |||
| 631 | } | |||
| 632 | ||||
| 633 | static const MemoryRegionOps lqspi_ops = { | |||
| 634 | .read = lqspi_read, | |||
| 635 | .endianness = DEVICE_NATIVE_ENDIAN, | |||
| 636 | .valid = { | |||
| 637 | .min_access_size = 1, | |||
| 638 | .max_access_size = 4 | |||
| 639 | } | |||
| 640 | }; | |||
| 641 | ||||
| 642 | static void xilinx_spips_realize(DeviceState *dev, Error **errp) | |||
| 643 | { | |||
| 644 | XilinxSPIPS *s = XILINX_SPIPS(dev)((XilinxSPIPS *)object_dynamic_cast_assert(((Object *)((dev)) ), ("xlnx.ps7-spi"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 644, __func__)); | |||
| 645 | SysBusDevice *sbd = SYS_BUS_DEVICE(dev)((SysBusDevice *)object_dynamic_cast_assert(((Object *)((dev) )), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 645, __func__)); | |||
| 646 | XilinxSPIPSClass *xsc = XILINX_SPIPS_GET_CLASS(s)((XilinxSPIPSClass *)object_class_dynamic_cast_assert(((ObjectClass *)(object_get_class(((Object *)((s)))))), ("xlnx.ps7-spi"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 646, __func__)); | |||
| 647 | int i; | |||
| 648 | ||||
| 649 | DB_PRINT_L(0, "realized spips\n")do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "realized spips\n"); } } while (0);; | |||
| 650 | ||||
| 651 | s->spi = g_new(SSIBus *, s->num_busses)((SSIBus * *) g_malloc_n ((s->num_busses), sizeof (SSIBus * ))); | |||
| 652 | for (i = 0; i < s->num_busses; ++i) { | |||
| 653 | char bus_name[16]; | |||
| 654 | snprintf(bus_name, 16, "spi%d", i); | |||
| 655 | s->spi[i] = ssi_create_bus(dev, bus_name); | |||
| 656 | } | |||
| 657 | ||||
| 658 | s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses)((qemu_irq *) g_malloc0_n ((s->num_cs * s->num_busses), sizeof (qemu_irq))); | |||
| 659 | ssi_auto_connect_slaves(DEVICE(s)((DeviceState *)object_dynamic_cast_assert(((Object *)((s))), ("device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 659, __func__)), s->cs_lines, s->spi[0]); | |||
| 660 | ssi_auto_connect_slaves(DEVICE(s)((DeviceState *)object_dynamic_cast_assert(((Object *)((s))), ("device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 660, __func__)), s->cs_lines, s->spi[1]); | |||
| 661 | sysbus_init_irq(sbd, &s->irq); | |||
| 662 | for (i = 0; i < s->num_cs * s->num_busses; ++i) { | |||
| 663 | sysbus_init_irq(sbd, &s->cs_lines[i]); | |||
| 664 | } | |||
| 665 | ||||
| 666 | memory_region_init_io(&s->iomem, OBJECT(s)((Object *)(s)), xsc->reg_ops, s, | |||
| 667 | "spi", R_MAX((0xFC / 4)+1)*4); | |||
| 668 | sysbus_init_mmio(sbd, &s->iomem); | |||
| 669 | ||||
| 670 | s->irqline = -1; | |||
| 671 | ||||
| 672 | fifo8_create(&s->rx_fifo, xsc->rx_fifo_size); | |||
| 673 | fifo8_create(&s->tx_fifo, xsc->tx_fifo_size); | |||
| 674 | } | |||
| 675 | ||||
| 676 | static void xilinx_qspips_realize(DeviceState *dev, Error **errp) | |||
| 677 | { | |||
| 678 | XilinxSPIPS *s = XILINX_SPIPS(dev)((XilinxSPIPS *)object_dynamic_cast_assert(((Object *)((dev)) ), ("xlnx.ps7-spi"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 678, __func__)); | |||
| 679 | XilinxQSPIPS *q = XILINX_QSPIPS(dev)((XilinxQSPIPS *)object_dynamic_cast_assert(((Object *)((dev) )), ("xlnx.ps7-qspi"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 679, __func__)); | |||
| 680 | SysBusDevice *sbd = SYS_BUS_DEVICE(dev)((SysBusDevice *)object_dynamic_cast_assert(((Object *)((dev) )), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 680, __func__)); | |||
| 681 | ||||
| 682 | DB_PRINT_L(0, "realized qspips\n")do { if (0 > (0)) { fprintf(stderr, ": %s: ", __func__); fprintf (stderr, "realized qspips\n"); } } while (0);; | |||
| 683 | ||||
| 684 | s->num_busses = 2; | |||
| 685 | s->num_cs = 2; | |||
| 686 | s->num_txrx_bytes = 4; | |||
| 687 | ||||
| 688 | xilinx_spips_realize(dev, errp); | |||
| 689 | memory_region_init_io(&s->mmlqspi, OBJECT(s)((Object *)(s)), &lqspi_ops, s, "lqspi", | |||
| 690 | (1 << LQSPI_ADDRESS_BITS24) * 2); | |||
| 691 | sysbus_init_mmio(sbd, &s->mmlqspi); | |||
| 692 | ||||
| 693 | q->lqspi_cached_addr = ~0ULL; | |||
| 694 | } | |||
| 695 | ||||
| 696 | static int xilinx_spips_post_load(void *opaque, int version_id) | |||
| 697 | { | |||
| 698 | xilinx_spips_update_ixr((XilinxSPIPS *)opaque); | |||
| 699 | xilinx_spips_update_cs_lines((XilinxSPIPS *)opaque); | |||
| 700 | return 0; | |||
| 701 | } | |||
| 702 | ||||
| 703 | static const VMStateDescription vmstate_xilinx_spips = { | |||
| 704 | .name = "xilinx_spips", | |||
| 705 | .version_id = 2, | |||
| 706 | .minimum_version_id = 2, | |||
| 707 | .minimum_version_id_old = 2, | |||
| 708 | .post_load = xilinx_spips_post_load, | |||
| 709 | .fields = (VMStateField[]) { | |||
| 710 | VMSTATE_FIFO8(tx_fifo, XilinxSPIPS){ .name = ("tx_fifo"), .size = sizeof(Fifo8), .vmsd = &vmstate_fifo8 , .flags = VMS_STRUCT, .offset = (__builtin_offsetof(XilinxSPIPS , tx_fifo) + ((Fifo8*)0 - (typeof(((XilinxSPIPS *)0)->tx_fifo )*)0)), }, | |||
| 711 | VMSTATE_FIFO8(rx_fifo, XilinxSPIPS){ .name = ("rx_fifo"), .size = sizeof(Fifo8), .vmsd = &vmstate_fifo8 , .flags = VMS_STRUCT, .offset = (__builtin_offsetof(XilinxSPIPS , rx_fifo) + ((Fifo8*)0 - (typeof(((XilinxSPIPS *)0)->rx_fifo )*)0)), }, | |||
| 712 | VMSTATE_UINT32_ARRAY(regs, XilinxSPIPS, R_MAX){ .name = ("regs"), .version_id = (0), .num = (((0xFC / 4)+1) ), .info = &(vmstate_info_uint32), .size = sizeof(uint32_t ), .flags = VMS_ARRAY, .offset = (__builtin_offsetof(XilinxSPIPS , regs) + ((uint32_t(*)[((0xFC / 4)+1)])0 - (typeof(((XilinxSPIPS *)0)->regs)*)0)), }, | |||
| 713 | VMSTATE_UINT8(snoop_state, XilinxSPIPS){ .name = ("snoop_state"), .version_id = (0), .field_exists = (((void*)0)), .size = sizeof(uint8_t), .info = &(vmstate_info_uint8 ), .flags = VMS_SINGLE, .offset = (__builtin_offsetof(XilinxSPIPS , snoop_state) + ((uint8_t*)0 - (typeof(((XilinxSPIPS *)0)-> snoop_state)*)0)), }, | |||
| 714 | VMSTATE_END_OF_LIST(){} | |||
| 715 | } | |||
| 716 | }; | |||
| 717 | ||||
| 718 | static Property xilinx_spips_properties[] = { | |||
| 719 | DEFINE_PROP_UINT8("num-busses", XilinxSPIPS, num_busses, 1){ .name = ("num-busses"), .info = &(qdev_prop_uint8), .offset = __builtin_offsetof(XilinxSPIPS, num_busses) + ((uint8_t*)0 - (typeof(((XilinxSPIPS *)0)->num_busses)*)0), .qtype = QTYPE_QINT , .defval = (uint8_t)1, }, | |||
| 720 | DEFINE_PROP_UINT8("num-ss-bits", XilinxSPIPS, num_cs, 4){ .name = ("num-ss-bits"), .info = &(qdev_prop_uint8), .offset = __builtin_offsetof(XilinxSPIPS, num_cs) + ((uint8_t*)0 - ( typeof(((XilinxSPIPS *)0)->num_cs)*)0), .qtype = QTYPE_QINT , .defval = (uint8_t)4, }, | |||
| 721 | DEFINE_PROP_UINT8("num-txrx-bytes", XilinxSPIPS, num_txrx_bytes, 1){ .name = ("num-txrx-bytes"), .info = &(qdev_prop_uint8), .offset = __builtin_offsetof(XilinxSPIPS, num_txrx_bytes) + ( (uint8_t*)0 - (typeof(((XilinxSPIPS *)0)->num_txrx_bytes)* )0), .qtype = QTYPE_QINT, .defval = (uint8_t)1, }, | |||
| 722 | DEFINE_PROP_END_OF_LIST(){}, | |||
| 723 | }; | |||
| 724 | ||||
| 725 | static void xilinx_qspips_class_init(ObjectClass *klass, void * data) | |||
| 726 | { | |||
| 727 | DeviceClass *dc = DEVICE_CLASS(klass)((DeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 727, __func__)); | |||
| 728 | XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass)((XilinxSPIPSClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("xlnx.ps7-spi"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 728, __func__)); | |||
| 729 | ||||
| 730 | dc->realize = xilinx_qspips_realize; | |||
| 731 | xsc->reg_ops = &qspips_ops; | |||
| 732 | xsc->rx_fifo_size = RXFF_A_Q(64 * 4); | |||
| 733 | xsc->tx_fifo_size = TXFF_A_Q(64 * 4); | |||
| 734 | } | |||
| 735 | ||||
| 736 | static void xilinx_spips_class_init(ObjectClass *klass, void *data) | |||
| 737 | { | |||
| 738 | DeviceClass *dc = DEVICE_CLASS(klass)((DeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 738, __func__)); | |||
| 739 | XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass)((XilinxSPIPSClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("xlnx.ps7-spi"), "/home/stefan/src/qemu/qemu.org/qemu/hw/ssi/xilinx_spips.c" , 739, __func__)); | |||
| 740 | ||||
| 741 | dc->realize = xilinx_spips_realize; | |||
| 742 | dc->reset = xilinx_spips_reset; | |||
| 743 | dc->props = xilinx_spips_properties; | |||
| 744 | dc->vmsd = &vmstate_xilinx_spips; | |||
| 745 | ||||
| 746 | xsc->reg_ops = &spips_ops; | |||
| 747 | xsc->rx_fifo_size = RXFF_A32; | |||
| 748 | xsc->tx_fifo_size = TXFF_A32; | |||
| 749 | } | |||
| 750 | ||||
| 751 | static const TypeInfo xilinx_spips_info = { | |||
| 752 | .name = TYPE_XILINX_SPIPS"xlnx.ps7-spi", | |||
| 753 | .parent = TYPE_SYS_BUS_DEVICE"sys-bus-device", | |||
| 754 | .instance_size = sizeof(XilinxSPIPS), | |||
| 755 | .class_init = xilinx_spips_class_init, | |||
| 756 | .class_size = sizeof(XilinxSPIPSClass), | |||
| 757 | }; | |||
| 758 | ||||
| 759 | static const TypeInfo xilinx_qspips_info = { | |||
| 760 | .name = TYPE_XILINX_QSPIPS"xlnx.ps7-qspi", | |||
| 761 | .parent = TYPE_XILINX_SPIPS"xlnx.ps7-spi", | |||
| 762 | .instance_size = sizeof(XilinxQSPIPS), | |||
| 763 | .class_init = xilinx_qspips_class_init, | |||
| 764 | }; | |||
| 765 | ||||
| 766 | static void xilinx_spips_register_types(void) | |||
| 767 | { | |||
| 768 | type_register_static(&xilinx_spips_info); | |||
| 769 | type_register_static(&xilinx_qspips_info); | |||
| 770 | } | |||
| 771 | ||||
| 772 | type_init(xilinx_spips_register_types)static void __attribute__((constructor)) do_qemu_init_xilinx_spips_register_types (void) { register_module_init(xilinx_spips_register_types, MODULE_INIT_QOM ); } |