]>
Commit | Line | Data |
---|---|---|
9d79e575 WW |
1 | /* |
2 | * (C) Copyright 2006 | |
3 | * Wolfgang Wegner, ASTRO Strobel Kommunikationssysteme GmbH, | |
4 | * w.wegner@astro-kom.de | |
5 | * | |
6 | * based on the files by | |
7 | * Heiko Schocher, DENX Software Engineering, hs@denx.de | |
8 | * and | |
9 | * Rich Ireland, Enterasys Networks, rireland@enterasys.com. | |
10 | * Keith Outwater, keith_outwater@mvis.com. | |
11 | * | |
1a459660 | 12 | * SPDX-License-Identifier: GPL-2.0+ |
9d79e575 WW |
13 | */ |
14 | ||
15 | /* Altera/Xilinx FPGA configuration support for the ASTRO "URMEL" board */ | |
16 | ||
17 | #include <common.h> | |
24b852a7 | 18 | #include <console.h> |
9d79e575 WW |
19 | #include <watchdog.h> |
20 | #include <altera.h> | |
21 | #include <ACEX1K.h> | |
22 | #include <spartan3.h> | |
23 | #include <command.h> | |
24 | #include <asm/immap_5329.h> | |
25 | #include <asm/io.h> | |
26 | #include "fpga.h" | |
27 | ||
28 | DECLARE_GLOBAL_DATA_PTR; | |
29 | ||
30 | int altera_pre_fn(int cookie) | |
31 | { | |
32 | gpio_t *gpiop = (gpio_t *)MMAP_GPIO; | |
33 | unsigned char tmp_char; | |
34 | unsigned short tmp_short; | |
35 | ||
36 | /* first, set the required pins to GPIO function */ | |
37 | /* PAR_T0IN -> GPIO */ | |
38 | tmp_char = readb(&gpiop->par_timer); | |
39 | tmp_char &= 0xfc; | |
40 | writeb(tmp_char, &gpiop->par_timer); | |
41 | /* all QSPI pins -> GPIO */ | |
42 | writew(0x0000, &gpiop->par_qspi); | |
43 | /* U0RTS, U0CTS -> GPIO */ | |
44 | tmp_short = __raw_readw(&gpiop->par_uart); | |
45 | tmp_short &= 0xfff3; | |
46 | __raw_writew(tmp_short, &gpiop->par_uart); | |
47 | /* all PWM pins -> GPIO */ | |
48 | writeb(0x00, &gpiop->par_pwm); | |
49 | /* next, set data direction registers */ | |
50 | writeb(0x01, &gpiop->pddr_timer); | |
51 | writeb(0x25, &gpiop->pddr_qspi); | |
52 | writeb(0x0c, &gpiop->pddr_uart); | |
53 | writeb(0x04, &gpiop->pddr_pwm); | |
54 | ||
55 | /* ensure other SPI peripherals are deselected */ | |
56 | writeb(0x08, &gpiop->ppd_uart); | |
57 | writeb(0x38, &gpiop->ppd_qspi); | |
58 | ||
59 | /* CONFIG = 0 STATUS = 0 -> FPGA in reset state */ | |
60 | writeb(0xFB, &gpiop->pclrr_uart); | |
61 | /* enable Altera configuration by clearing QSPI_CS2 and DT0IN */ | |
62 | writeb(0xFE, &gpiop->pclrr_timer); | |
63 | writeb(0xDF, &gpiop->pclrr_qspi); | |
64 | return FPGA_SUCCESS; | |
65 | } | |
66 | ||
67 | /* Set the state of CONFIG Pin */ | |
68 | int altera_config_fn(int assert_config, int flush, int cookie) | |
69 | { | |
70 | gpio_t *gpiop = (gpio_t *)MMAP_GPIO; | |
71 | ||
72 | if (assert_config) | |
73 | writeb(0x04, &gpiop->ppd_uart); | |
74 | else | |
75 | writeb(0xFB, &gpiop->pclrr_uart); | |
76 | return FPGA_SUCCESS; | |
77 | } | |
78 | ||
79 | /* Returns the state of STATUS Pin */ | |
80 | int altera_status_fn(int cookie) | |
81 | { | |
82 | gpio_t *gpiop = (gpio_t *)MMAP_GPIO; | |
83 | ||
84 | if (readb(&gpiop->ppd_pwm) & 0x08) | |
85 | return FPGA_FAIL; | |
86 | return FPGA_SUCCESS; | |
87 | } | |
88 | ||
89 | /* Returns the state of CONF_DONE Pin */ | |
90 | int altera_done_fn(int cookie) | |
91 | { | |
92 | gpio_t *gpiop = (gpio_t *)MMAP_GPIO; | |
93 | ||
94 | if (readb(&gpiop->ppd_pwm) & 0x20) | |
95 | return FPGA_FAIL; | |
96 | return FPGA_SUCCESS; | |
97 | } | |
98 | ||
99 | /* | |
100 | * writes the complete buffer to the FPGA | |
101 | * writing the complete buffer in one function is much faster, | |
102 | * then calling it for every bit | |
103 | */ | |
ddc94378 | 104 | int altera_write_fn(const void *buf, size_t len, int flush, int cookie) |
9d79e575 WW |
105 | { |
106 | size_t bytecount = 0; | |
107 | gpio_t *gpiop = (gpio_t *)MMAP_GPIO; | |
108 | unsigned char *data = (unsigned char *)buf; | |
109 | unsigned char val = 0; | |
110 | int i; | |
111 | int len_40 = len / 40; | |
112 | ||
113 | while (bytecount < len) { | |
114 | val = data[bytecount++]; | |
115 | i = 8; | |
116 | do { | |
117 | writeb(0xFB, &gpiop->pclrr_qspi); | |
118 | if (val & 0x01) | |
119 | writeb(0x01, &gpiop->ppd_qspi); | |
120 | else | |
121 | writeb(0xFE, &gpiop->pclrr_qspi); | |
122 | writeb(0x04, &gpiop->ppd_qspi); | |
123 | val >>= 1; | |
124 | i--; | |
125 | } while (i > 0); | |
126 | ||
127 | if (bytecount % len_40 == 0) { | |
128 | #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) | |
129 | WATCHDOG_RESET(); | |
130 | #endif | |
131 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK | |
132 | putc('.'); /* let them know we are alive */ | |
133 | #endif | |
134 | #ifdef CONFIG_SYS_FPGA_CHECK_CTRLC | |
135 | if (ctrlc()) | |
136 | return FPGA_FAIL; | |
137 | #endif | |
138 | } | |
139 | } | |
140 | return FPGA_SUCCESS; | |
141 | } | |
142 | ||
143 | /* called, when programming is aborted */ | |
144 | int altera_abort_fn(int cookie) | |
145 | { | |
146 | gpio_t *gpiop = (gpio_t *)MMAP_GPIO; | |
147 | ||
148 | writeb(0x20, &gpiop->ppd_qspi); | |
149 | writeb(0x08, &gpiop->ppd_uart); | |
150 | return FPGA_SUCCESS; | |
151 | } | |
152 | ||
153 | /* called, when programming was succesful */ | |
154 | int altera_post_fn(int cookie) | |
155 | { | |
156 | return altera_abort_fn(cookie); | |
157 | } | |
158 | ||
159 | /* | |
160 | * Note that these are pointers to code that is in Flash. They will be | |
161 | * relocated at runtime. | |
162 | * FIXME: relocation not yet working for coldfire, see below! | |
163 | */ | |
164 | Altera_CYC2_Passive_Serial_fns altera_fns = { | |
165 | altera_pre_fn, | |
166 | altera_config_fn, | |
167 | altera_status_fn, | |
168 | altera_done_fn, | |
169 | altera_write_fn, | |
170 | altera_abort_fn, | |
171 | altera_post_fn | |
172 | }; | |
173 | ||
174 | Altera_desc altera_fpga[CONFIG_FPGA_COUNT] = { | |
175 | {Altera_CYC2, | |
176 | passive_serial, | |
177 | 85903, | |
178 | (void *)&altera_fns, | |
179 | NULL, | |
180 | 0} | |
181 | }; | |
182 | ||
183 | /* Initialize the fpga. Return 1 on success, 0 on failure. */ | |
184 | int astro5373l_altera_load(void) | |
185 | { | |
186 | int i; | |
187 | ||
188 | for (i = 0; i < CONFIG_FPGA_COUNT; i++) { | |
189 | /* | |
190 | * I did not yet manage to get relocation work properly, | |
191 | * so set stuff here instead of static initialisation: | |
192 | */ | |
193 | altera_fns.pre = altera_pre_fn; | |
194 | altera_fns.config = altera_config_fn; | |
195 | altera_fns.status = altera_status_fn; | |
196 | altera_fns.done = altera_done_fn; | |
197 | altera_fns.write = altera_write_fn; | |
198 | altera_fns.abort = altera_abort_fn; | |
199 | altera_fns.post = altera_post_fn; | |
200 | altera_fpga[i].iface_fns = (void *)&altera_fns; | |
201 | fpga_add(fpga_altera, &altera_fpga[i]); | |
202 | } | |
203 | return 1; | |
204 | } | |
205 | ||
206 | /* Set the FPGA's PROG_B line to the specified level */ | |
2df9d5c4 | 207 | int xilinx_pgm_config_fn(int assert, int flush, int cookie) |
9d79e575 WW |
208 | { |
209 | gpio_t *gpiop = (gpio_t *)MMAP_GPIO; | |
210 | ||
211 | if (assert) | |
212 | writeb(0xFB, &gpiop->pclrr_uart); | |
213 | else | |
214 | writeb(0x04, &gpiop->ppd_uart); | |
215 | return assert; | |
216 | } | |
217 | ||
218 | /* | |
219 | * Test the state of the active-low FPGA INIT line. Return 1 on INIT | |
220 | * asserted (low). | |
221 | */ | |
2df9d5c4 | 222 | int xilinx_init_config_fn(int cookie) |
9d79e575 WW |
223 | { |
224 | gpio_t *gpiop = (gpio_t *)MMAP_GPIO; | |
225 | ||
226 | return (readb(&gpiop->ppd_pwm) & 0x08) == 0; | |
227 | } | |
228 | ||
229 | /* Test the state of the active-high FPGA DONE pin */ | |
2df9d5c4 | 230 | int xilinx_done_config_fn(int cookie) |
9d79e575 WW |
231 | { |
232 | gpio_t *gpiop = (gpio_t *)MMAP_GPIO; | |
233 | ||
234 | return (readb(&gpiop->ppd_pwm) & 0x20) >> 5; | |
235 | } | |
236 | ||
237 | /* Abort an FPGA operation */ | |
2df9d5c4 | 238 | int xilinx_abort_config_fn(int cookie) |
9d79e575 WW |
239 | { |
240 | gpio_t *gpiop = (gpio_t *)MMAP_GPIO; | |
241 | /* ensure all SPI peripherals and FPGAs are deselected */ | |
242 | writeb(0x08, &gpiop->ppd_uart); | |
243 | writeb(0x01, &gpiop->ppd_timer); | |
244 | writeb(0x38, &gpiop->ppd_qspi); | |
245 | return FPGA_FAIL; | |
246 | } | |
247 | ||
248 | /* | |
249 | * FPGA pre-configuration function. Just make sure that | |
250 | * FPGA reset is asserted to keep the FPGA from starting up after | |
251 | * configuration. | |
252 | */ | |
253 | int xilinx_pre_config_fn(int cookie) | |
254 | { | |
255 | gpio_t *gpiop = (gpio_t *)MMAP_GPIO; | |
256 | unsigned char tmp_char; | |
257 | unsigned short tmp_short; | |
258 | ||
259 | /* first, set the required pins to GPIO function */ | |
260 | /* PAR_T0IN -> GPIO */ | |
261 | tmp_char = readb(&gpiop->par_timer); | |
262 | tmp_char &= 0xfc; | |
263 | writeb(tmp_char, &gpiop->par_timer); | |
264 | /* all QSPI pins -> GPIO */ | |
265 | writew(0x0000, &gpiop->par_qspi); | |
266 | /* U0RTS, U0CTS -> GPIO */ | |
267 | tmp_short = __raw_readw(&gpiop->par_uart); | |
268 | tmp_short &= 0xfff3; | |
269 | __raw_writew(tmp_short, &gpiop->par_uart); | |
270 | /* all PWM pins -> GPIO */ | |
271 | writeb(0x00, &gpiop->par_pwm); | |
272 | /* next, set data direction registers */ | |
273 | writeb(0x01, &gpiop->pddr_timer); | |
274 | writeb(0x25, &gpiop->pddr_qspi); | |
275 | writeb(0x0c, &gpiop->pddr_uart); | |
276 | writeb(0x04, &gpiop->pddr_pwm); | |
277 | ||
278 | /* ensure other SPI peripherals are deselected */ | |
279 | writeb(0x08, &gpiop->ppd_uart); | |
280 | writeb(0x38, &gpiop->ppd_qspi); | |
281 | writeb(0x01, &gpiop->ppd_timer); | |
282 | ||
283 | /* CONFIG = 0, STATUS = 0 -> FPGA in reset state */ | |
284 | writeb(0xFB, &gpiop->pclrr_uart); | |
285 | /* enable Xilinx configuration by clearing QSPI_CS2 and U0CTS */ | |
286 | writeb(0xF7, &gpiop->pclrr_uart); | |
287 | writeb(0xDF, &gpiop->pclrr_qspi); | |
288 | return 0; | |
289 | } | |
290 | ||
291 | /* | |
292 | * FPGA post configuration function. Should perform a test if FPGA is running. | |
293 | */ | |
294 | int xilinx_post_config_fn(int cookie) | |
295 | { | |
296 | int rc = 0; | |
297 | ||
298 | /* | |
299 | * no test yet | |
300 | */ | |
301 | return rc; | |
302 | } | |
303 | ||
2df9d5c4 | 304 | int xilinx_clk_config_fn(int assert_clk, int flush, int cookie) |
9d79e575 WW |
305 | { |
306 | gpio_t *gpiop = (gpio_t *)MMAP_GPIO; | |
307 | ||
308 | if (assert_clk) | |
309 | writeb(0x04, &gpiop->ppd_qspi); | |
310 | else | |
311 | writeb(0xFB, &gpiop->pclrr_qspi); | |
312 | return assert_clk; | |
313 | } | |
314 | ||
2df9d5c4 | 315 | int xilinx_wr_config_fn(int assert_write, int flush, int cookie) |
9d79e575 WW |
316 | { |
317 | gpio_t *gpiop = (gpio_t *)MMAP_GPIO; | |
318 | ||
319 | if (assert_write) | |
320 | writeb(0x01, &gpiop->ppd_qspi); | |
321 | else | |
322 | writeb(0xFE, &gpiop->pclrr_qspi); | |
323 | return assert_write; | |
324 | } | |
325 | ||
2df9d5c4 | 326 | int xilinx_fastwr_config_fn(void *buf, size_t len, int flush, int cookie) |
9d79e575 WW |
327 | { |
328 | size_t bytecount = 0; | |
329 | gpio_t *gpiop = (gpio_t *)MMAP_GPIO; | |
330 | unsigned char *data = (unsigned char *)buf; | |
331 | unsigned char val = 0; | |
332 | int i; | |
333 | int len_40 = len / 40; | |
334 | ||
335 | for (bytecount = 0; bytecount < len; bytecount++) { | |
336 | val = *(data++); | |
337 | for (i = 8; i > 0; i--) { | |
338 | writeb(0xFB, &gpiop->pclrr_qspi); | |
339 | if (val & 0x80) | |
340 | writeb(0x01, &gpiop->ppd_qspi); | |
341 | else | |
342 | writeb(0xFE, &gpiop->pclrr_qspi); | |
343 | writeb(0x04, &gpiop->ppd_qspi); | |
344 | val <<= 1; | |
345 | } | |
346 | if (bytecount % len_40 == 0) { | |
347 | #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) | |
348 | WATCHDOG_RESET(); | |
349 | #endif | |
350 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK | |
351 | putc('.'); /* let them know we are alive */ | |
352 | #endif | |
353 | #ifdef CONFIG_SYS_FPGA_CHECK_CTRLC | |
354 | if (ctrlc()) | |
355 | return FPGA_FAIL; | |
356 | #endif | |
357 | } | |
358 | } | |
359 | return FPGA_SUCCESS; | |
360 | } | |
361 | ||
362 | /* | |
363 | * Note that these are pointers to code that is in Flash. They will be | |
364 | * relocated at runtime. | |
365 | * FIXME: relocation not yet working for coldfire, see below! | |
366 | */ | |
2a6e3869 | 367 | xilinx_spartan3_slave_serial_fns xilinx_fns = { |
9d79e575 | 368 | xilinx_pre_config_fn, |
2df9d5c4 MS |
369 | xilinx_pgm_config_fn, |
370 | xilinx_clk_config_fn, | |
371 | xilinx_init_config_fn, | |
372 | xilinx_done_config_fn, | |
373 | xilinx_wr_config_fn, | |
9d79e575 | 374 | 0, |
2df9d5c4 | 375 | xilinx_fastwr_config_fn |
9d79e575 WW |
376 | }; |
377 | ||
f8c1be98 | 378 | xilinx_desc xilinx_fpga[CONFIG_FPGA_COUNT] = { |
2a6e3869 | 379 | {xilinx_spartan3, |
9d79e575 WW |
380 | slave_serial, |
381 | XILINX_XC3S4000_SIZE, | |
382 | (void *)&xilinx_fns, | |
14cfc4f3 MS |
383 | 0, |
384 | &spartan3_op} | |
9d79e575 WW |
385 | }; |
386 | ||
387 | /* Initialize the fpga. Return 1 on success, 0 on failure. */ | |
388 | int astro5373l_xilinx_load(void) | |
389 | { | |
390 | int i; | |
391 | ||
392 | fpga_init(); | |
393 | ||
394 | for (i = 0; i < CONFIG_FPGA_COUNT; i++) { | |
395 | /* | |
396 | * I did not yet manage to get relocation work properly, | |
397 | * so set stuff here instead of static initialisation: | |
398 | */ | |
399 | xilinx_fns.pre = xilinx_pre_config_fn; | |
2df9d5c4 MS |
400 | xilinx_fns.pgm = xilinx_pgm_config_fn; |
401 | xilinx_fns.clk = xilinx_clk_config_fn; | |
402 | xilinx_fns.init = xilinx_init_config_fn; | |
403 | xilinx_fns.done = xilinx_done_config_fn; | |
404 | xilinx_fns.wr = xilinx_wr_config_fn; | |
405 | xilinx_fns.bwr = xilinx_fastwr_config_fn; | |
9d79e575 WW |
406 | xilinx_fpga[i].iface_fns = (void *)&xilinx_fns; |
407 | fpga_add(fpga_xilinx, &xilinx_fpga[i]); | |
408 | } | |
409 | return 1; | |
410 | } |