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