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