]>
Commit | Line | Data |
---|---|---|
c609719b WD |
1 | /* |
2 | * (C) Copyright 2002 | |
3 | * Rich Ireland, Enterasys Networks, rireland@enterasys.com. | |
4 | * Keith Outwater, keith_outwater@mvis.com. | |
5 | * | |
1a459660 | 6 | * SPDX-License-Identifier: GPL-2.0+ |
c609719b WD |
7 | */ |
8 | ||
9 | /* | |
10 | * Virtex2 FPGA configuration support for the GEN860T computer | |
11 | */ | |
12 | ||
13 | #include <common.h> | |
14 | #include <virtex2.h> | |
15 | #include <command.h> | |
16 | #include "fpga.h" | |
17 | ||
d87080b7 WD |
18 | DECLARE_GLOBAL_DATA_PTR; |
19 | ||
0133502e | 20 | #if defined(CONFIG_FPGA) |
c609719b WD |
21 | |
22 | #if 0 | |
23 | #define GEN860T_FPGA_DEBUG | |
24 | #endif | |
25 | ||
26 | #ifdef GEN860T_FPGA_DEBUG | |
27 | #define PRINTF(fmt,args...) printf (fmt ,##args) | |
28 | #else | |
29 | #define PRINTF(fmt,args...) | |
30 | #endif | |
31 | ||
32 | /* | |
33 | * Port bit numbers for the Selectmap controls | |
34 | */ | |
35 | #define FPGA_INIT_BIT_NUM 22 /* PB22 */ | |
36 | #define FPGA_RESET_BIT_NUM 11 /* PC11 */ | |
37 | #define FPGA_DONE_BIT_NUM 16 /* PB16 */ | |
38 | #define FPGA_PROGRAM_BIT_NUM 7 /* PA7 */ | |
39 | ||
40 | /* Note that these are pointers to code that is in Flash. They will be | |
41 | * relocated at runtime. | |
42 | */ | |
d9071ce0 | 43 | xilinx_virtex2_slave_selectmap_fns fpga_fns = { |
c609719b WD |
44 | fpga_pre_config_fn, |
45 | fpga_pgm_fn, | |
46 | fpga_init_fn, | |
47 | fpga_err_fn, | |
48 | fpga_done_fn, | |
49 | fpga_clk_fn, | |
50 | fpga_cs_fn, | |
51 | fpga_wr_fn, | |
52 | fpga_read_data_fn, | |
53 | fpga_write_data_fn, | |
54 | fpga_busy_fn, | |
55 | fpga_abort_fn, | |
56 | fpga_post_config_fn | |
57 | }; | |
58 | ||
f8c1be98 | 59 | xilinx_desc fpga[CONFIG_FPGA_COUNT] = { |
d9071ce0 | 60 | {xilinx_virtex2, |
bf9e3b38 WD |
61 | slave_selectmap, |
62 | XILINX_XC2V3000_SIZE, | |
63 | (void *) &fpga_fns, | |
64 | 0} | |
c609719b WD |
65 | }; |
66 | ||
67 | /* | |
68 | * Display FPGA revision information | |
69 | */ | |
bf9e3b38 | 70 | void print_fpga_revision (void) |
c609719b | 71 | { |
bf9e3b38 WD |
72 | vu_long *rev_p = (vu_long *) 0x60000008; |
73 | ||
74 | printf ("FPGA Revision 0x%.8lx" | |
75 | " (Date %.2lx/%.2lx/%.2lx, Status \"%.1lx\", Version %.3lu)\n", | |
76 | *rev_p, | |
77 | ((*rev_p >> 28) & 0xf), | |
78 | ((*rev_p >> 20) & 0xff), | |
79 | ((*rev_p >> 12) & 0xff), | |
80 | ((*rev_p >> 8) & 0xf), (*rev_p & 0xff)); | |
c609719b WD |
81 | } |
82 | ||
83 | ||
84 | /* | |
85 | * Perform a simple test of the FPGA to processor interface using the FPGA's | |
86 | * inverting bus test register. The great thing about doing a read/write | |
87 | * test on a register that inverts it's contents is that you avoid any | |
88 | * problems with bus charging. | |
89 | * Return 0 on failure, 1 on success. | |
90 | */ | |
bf9e3b38 | 91 | int test_fpga_ibtr (void) |
c609719b | 92 | { |
bf9e3b38 | 93 | vu_long *ibtr_p = (vu_long *) 0x60000010; |
c609719b WD |
94 | vu_long readback; |
95 | vu_long compare; | |
96 | int i; | |
97 | int j; | |
98 | int k; | |
99 | int pass = 1; | |
100 | ||
101 | static const ulong bitpattern[] = { | |
bf9e3b38 WD |
102 | 0xdeadbeef, /* magic ID pattern for debug */ |
103 | 0x00000001, /* single bit */ | |
104 | 0x00000003, /* two adjacent bits */ | |
105 | 0x00000007, /* three adjacent bits */ | |
106 | 0x0000000F, /* four adjacent bits */ | |
107 | 0x00000005, /* two non-adjacent bits */ | |
108 | 0x00000015, /* three non-adjacent bits */ | |
109 | 0x00000055, /* four non-adjacent bits */ | |
110 | 0xaaaaaaaa, /* alternating 1/0 */ | |
c609719b WD |
111 | }; |
112 | ||
113 | for (i = 0; i < 1024; i++) { | |
114 | for (j = 0; j < 31; j++) { | |
bf9e3b38 WD |
115 | for (k = 0; |
116 | k < sizeof (bitpattern) / sizeof (bitpattern[0]); | |
117 | k++) { | |
c609719b WD |
118 | *ibtr_p = compare = (bitpattern[k] << j); |
119 | readback = *ibtr_p; | |
120 | if (readback != ~compare) { | |
bf9e3b38 | 121 | printf ("%s:%d: FPGA test fail: expected 0x%.8lx" " actual 0x%.8lx\n", __FUNCTION__, __LINE__, ~compare, readback); |
c609719b WD |
122 | pass = 0; |
123 | break; | |
124 | } | |
125 | } | |
bf9e3b38 WD |
126 | if (!pass) |
127 | break; | |
c609719b | 128 | } |
bf9e3b38 WD |
129 | if (!pass) |
130 | break; | |
c609719b WD |
131 | } |
132 | if (pass) { | |
bf9e3b38 WD |
133 | printf ("FPGA inverting bus test passed\n"); |
134 | print_fpga_revision (); | |
135 | } else { | |
136 | printf ("** FPGA inverting bus test failed\n"); | |
c609719b WD |
137 | } |
138 | return pass; | |
139 | } | |
140 | ||
141 | ||
142 | /* | |
143 | * Set the active-low FPGA reset signal. | |
144 | */ | |
bf9e3b38 | 145 | void fpga_reset (int assert) |
c609719b | 146 | { |
6d0f6bcf | 147 | volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; |
c609719b | 148 | |
bf9e3b38 | 149 | PRINTF ("%s:%d: RESET ", __FUNCTION__, __LINE__); |
c609719b WD |
150 | if (assert) { |
151 | immap->im_ioport.iop_pcdat &= ~(0x8000 >> FPGA_RESET_BIT_NUM); | |
bf9e3b38 WD |
152 | PRINTF ("asserted\n"); |
153 | } else { | |
c609719b | 154 | immap->im_ioport.iop_pcdat |= (0x8000 >> FPGA_RESET_BIT_NUM); |
bf9e3b38 | 155 | PRINTF ("deasserted\n"); |
c609719b WD |
156 | } |
157 | } | |
158 | ||
159 | ||
160 | /* | |
161 | * Initialize the SelectMap interface. We assume that the mode and the | |
162 | * initial state of all of the port pins have already been set! | |
163 | */ | |
bf9e3b38 | 164 | void fpga_selectmap_init (void) |
c609719b | 165 | { |
bf9e3b38 WD |
166 | PRINTF ("%s:%d: Initialize SelectMap interface\n", __FUNCTION__, |
167 | __LINE__); | |
472d5460 | 168 | fpga_pgm_fn(false, false, 0); /* make sure program pin is inactive */ |
c609719b WD |
169 | } |
170 | ||
171 | ||
172 | /* | |
173 | * Initialize the fpga. Return 1 on success, 0 on failure. | |
174 | */ | |
bf9e3b38 | 175 | int gen860t_init_fpga (void) |
c609719b | 176 | { |
c609719b WD |
177 | int i; |
178 | ||
6385b281 PT |
179 | PRINTF ("%s:%d: Initialize FPGA interface\n", |
180 | __FUNCTION__, __LINE__); | |
181 | fpga_init (); | |
bf9e3b38 | 182 | fpga_selectmap_init (); |
c609719b | 183 | |
bf9e3b38 WD |
184 | for (i = 0; i < CONFIG_FPGA_COUNT; i++) { |
185 | PRINTF ("%s:%d: Adding fpga %d\n", __FUNCTION__, __LINE__, i); | |
186 | fpga_add (fpga_xilinx, &fpga[i]); | |
c609719b | 187 | } |
bf9e3b38 | 188 | return 1; |
c609719b WD |
189 | } |
190 | ||
191 | ||
192 | /* | |
193 | * Set the FPGA's active-low SelectMap program line to the specified level | |
194 | */ | |
bf9e3b38 | 195 | int fpga_pgm_fn (int assert, int flush, int cookie) |
c609719b | 196 | { |
6d0f6bcf | 197 | volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; |
c609719b | 198 | |
bf9e3b38 | 199 | PRINTF ("%s:%d: FPGA PROGRAM ", __FUNCTION__, __LINE__); |
c609719b WD |
200 | |
201 | if (assert) { | |
bf9e3b38 WD |
202 | immap->im_ioport.iop_padat &= |
203 | ~(0x8000 >> FPGA_PROGRAM_BIT_NUM); | |
204 | PRINTF ("asserted\n"); | |
205 | } else { | |
206 | immap->im_ioport.iop_padat |= | |
207 | (0x8000 >> FPGA_PROGRAM_BIT_NUM); | |
208 | PRINTF ("deasserted\n"); | |
c609719b WD |
209 | } |
210 | return assert; | |
211 | } | |
212 | ||
213 | ||
214 | /* | |
215 | * Test the state of the active-low FPGA INIT line. Return 1 on INIT | |
216 | * asserted (low). | |
217 | */ | |
bf9e3b38 | 218 | int fpga_init_fn (int cookie) |
c609719b | 219 | { |
6d0f6bcf | 220 | volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; |
c609719b | 221 | |
bf9e3b38 WD |
222 | PRINTF ("%s:%d: INIT check... ", __FUNCTION__, __LINE__); |
223 | if (immap->im_cpm.cp_pbdat & (0x80000000 >> FPGA_INIT_BIT_NUM)) { | |
224 | PRINTF ("high\n"); | |
c609719b | 225 | return 0; |
bf9e3b38 WD |
226 | } else { |
227 | PRINTF ("low\n"); | |
c609719b WD |
228 | return 1; |
229 | } | |
230 | } | |
231 | ||
232 | ||
233 | /* | |
234 | * Test the state of the active-high FPGA DONE pin | |
235 | */ | |
bf9e3b38 | 236 | int fpga_done_fn (int cookie) |
c609719b | 237 | { |
6d0f6bcf | 238 | volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; |
c609719b | 239 | |
bf9e3b38 | 240 | PRINTF ("%s:%d: DONE check... ", __FUNCTION__, __LINE__); |
c609719b | 241 | if (immap->im_cpm.cp_pbdat & (0x80000000 >> FPGA_DONE_BIT_NUM)) { |
bf9e3b38 | 242 | PRINTF ("high\n"); |
c609719b | 243 | return FPGA_SUCCESS; |
bf9e3b38 WD |
244 | } else { |
245 | PRINTF ("low\n"); | |
c609719b WD |
246 | return FPGA_FAIL; |
247 | } | |
248 | } | |
249 | ||
250 | ||
251 | /* | |
252 | * Read FPGA SelectMap data. | |
253 | */ | |
bf9e3b38 | 254 | int fpga_read_data_fn (unsigned char *data, int cookie) |
c609719b | 255 | { |
bf9e3b38 | 256 | vu_char *p = (vu_char *) SELECTMAP_BASE; |
c609719b WD |
257 | |
258 | *data = *p; | |
259 | #if 0 | |
bf9e3b38 | 260 | PRINTF ("%s: Read 0x%x into 0x%p\n", __FUNCTION__, (int) data, data); |
c609719b | 261 | #endif |
bf9e3b38 | 262 | return (int) data; |
c609719b WD |
263 | } |
264 | ||
265 | ||
266 | /* | |
267 | * Write data to the FPGA SelectMap port | |
268 | */ | |
bf9e3b38 | 269 | int fpga_write_data_fn (unsigned char data, int flush, int cookie) |
c609719b | 270 | { |
bf9e3b38 | 271 | vu_char *p = (vu_char *) SELECTMAP_BASE; |
c609719b WD |
272 | |
273 | #if 0 | |
bf9e3b38 | 274 | PRINTF ("%s: Write Data 0x%x\n", __FUNCTION__, (int) data); |
c609719b WD |
275 | #endif |
276 | *p = data; | |
bf9e3b38 | 277 | return (int) data; |
c609719b WD |
278 | } |
279 | ||
280 | ||
281 | /* | |
282 | * Abort and FPGA operation | |
283 | */ | |
bf9e3b38 | 284 | int fpga_abort_fn (int cookie) |
c609719b | 285 | { |
bf9e3b38 WD |
286 | PRINTF ("%s:%d: FPGA program sequence aborted\n", |
287 | __FUNCTION__, __LINE__); | |
c609719b WD |
288 | return FPGA_FAIL; |
289 | } | |
290 | ||
291 | ||
292 | /* | |
293 | * FPGA pre-configuration function. Just make sure that | |
294 | * FPGA reset is asserted to keep the FPGA from starting up after | |
295 | * configuration. | |
296 | */ | |
bf9e3b38 | 297 | int fpga_pre_config_fn (int cookie) |
c609719b | 298 | { |
bf9e3b38 | 299 | PRINTF ("%s:%d: FPGA pre-configuration\n", __FUNCTION__, __LINE__); |
472d5460 | 300 | fpga_reset(true); |
c609719b WD |
301 | return 0; |
302 | } | |
303 | ||
304 | ||
305 | /* | |
306 | * FPGA post configuration function. Blip the FPGA reset line and then see if | |
307 | * the FPGA appears to be running. | |
308 | */ | |
bf9e3b38 | 309 | int fpga_post_config_fn (int cookie) |
c609719b WD |
310 | { |
311 | int rc; | |
312 | ||
bf9e3b38 | 313 | PRINTF ("%s:%d: FPGA post configuration\n", __FUNCTION__, __LINE__); |
472d5460 | 314 | fpga_reset(true); |
bf9e3b38 | 315 | udelay (1000); |
472d5460 | 316 | fpga_reset(false); |
c609719b WD |
317 | udelay (1000); |
318 | ||
319 | /* | |
320 | * Use the FPGA,s inverting bus test register to do a simple test of the | |
321 | * processor interface. | |
322 | */ | |
bf9e3b38 | 323 | rc = test_fpga_ibtr (); |
c609719b WD |
324 | return rc; |
325 | } | |
326 | ||
327 | ||
328 | /* | |
329 | * Clock, chip select and write signal assert functions and error check | |
330 | * and busy functions. These are only stubs because the GEN860T selectmap | |
331 | * interface handles sequencing of control signals automatically (it uses | |
332 | * a memory-mapped interface to the FPGA SelectMap port). The design of | |
333 | * the interface guarantees that the SelectMap port cannot be overrun so | |
334 | * no busy check is needed. A configuration error is signalled by INIT | |
335 | * going low during configuration, so there is no need for a separate error | |
336 | * function. | |
337 | */ | |
bf9e3b38 | 338 | int fpga_clk_fn (int assert_clk, int flush, int cookie) |
c609719b WD |
339 | { |
340 | return assert_clk; | |
341 | } | |
342 | ||
bf9e3b38 | 343 | int fpga_cs_fn (int assert_cs, int flush, int cookie) |
c609719b WD |
344 | { |
345 | return assert_cs; | |
346 | } | |
347 | ||
bf9e3b38 | 348 | int fpga_wr_fn (int assert_write, int flush, int cookie) |
c609719b WD |
349 | { |
350 | return assert_write; | |
351 | } | |
352 | ||
bf9e3b38 | 353 | int fpga_err_fn (int cookie) |
c609719b WD |
354 | { |
355 | return 0; | |
356 | } | |
357 | ||
bf9e3b38 | 358 | int fpga_busy_fn (int cookie) |
c609719b WD |
359 | { |
360 | return 0; | |
361 | } | |
362 | #endif |