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 ); } |