]>
Commit | Line | Data |
---|---|---|
c609719b WD |
1 | /* |
2 | * (C) Copyright 2002 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | * | |
5 | * (C) Copyright 2002 | |
6 | * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
7 | * Marius Groeger <mgroeger@sysgo.de> | |
8 | * | |
9 | * See file CREDITS for list of people who contributed to this | |
10 | * project. | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or | |
13 | * modify it under the terms of the GNU General Public License as | |
14 | * published by the Free Software Foundation; either version 2 of | |
15 | * the License, or (at your option) any later version. | |
16 | * | |
17 | * This program is distributed in the hope that it will be useful, | |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | * GNU General Public License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU General Public License | |
23 | * along with this program; if not, write to the Free Software | |
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
25 | * MA 02111-1307 USA | |
26 | */ | |
27 | ||
28 | #include <common.h> | |
29 | #include <command.h> | |
30 | #include <devices.h> | |
31 | #include <version.h> | |
32 | #include <net.h> | |
33 | ||
dc7c9a1a WD |
34 | #if (CONFIG_COMMANDS & CFG_CMD_NAND) |
35 | void nand_init (void); | |
36 | #endif | |
c609719b | 37 | |
3b57fe0a WD |
38 | ulong monitor_flash_len; |
39 | ||
2abbe075 WD |
40 | #ifdef CONFIG_HAS_DATAFLASH |
41 | extern int AT91F_DataflashInit(void); | |
42 | extern void dataflash_print_info(void); | |
43 | #endif | |
44 | ||
48b42616 WD |
45 | #ifndef CONFIG_IDENT_STRING |
46 | #define CONFIG_IDENT_STRING "" | |
47 | #endif | |
48 | ||
c609719b | 49 | const char version_string[] = |
48b42616 | 50 | U_BOOT_VERSION" (" __DATE__ " - " __TIME__ ")"CONFIG_IDENT_STRING; |
c609719b WD |
51 | |
52 | #ifdef CONFIG_DRIVER_CS8900 | |
53 | extern void cs8900_get_enetaddr (uchar * addr); | |
54 | #endif | |
55 | ||
45219c46 WD |
56 | #ifdef CONFIG_DRIVER_LAN91C96 |
57 | #include "../drivers/lan91c96.h" | |
58 | #endif | |
c609719b WD |
59 | /* |
60 | * Begin and End of memory area for malloc(), and current "brk" | |
61 | */ | |
62 | static ulong mem_malloc_start = 0; | |
63 | static ulong mem_malloc_end = 0; | |
64 | static ulong mem_malloc_brk = 0; | |
65 | ||
a6c7ad2f | 66 | static |
a6c7ad2f | 67 | void mem_malloc_init (ulong dest_addr) |
c609719b WD |
68 | { |
69 | mem_malloc_start = dest_addr; | |
699b13a6 | 70 | mem_malloc_end = dest_addr + CFG_MALLOC_LEN; |
c609719b WD |
71 | mem_malloc_brk = mem_malloc_start; |
72 | ||
73 | memset ((void *) mem_malloc_start, 0, | |
74 | mem_malloc_end - mem_malloc_start); | |
75 | } | |
76 | ||
77 | void *sbrk (ptrdiff_t increment) | |
78 | { | |
79 | ulong old = mem_malloc_brk; | |
80 | ulong new = old + increment; | |
81 | ||
82 | if ((new < mem_malloc_start) || (new > mem_malloc_end)) { | |
83 | return (NULL); | |
84 | } | |
85 | mem_malloc_brk = new; | |
86 | ||
87 | return ((void *) old); | |
88 | } | |
89 | ||
90 | /************************************************************************ | |
91 | * Init Utilities * | |
92 | ************************************************************************ | |
93 | * Some of this code should be moved into the core functions, | |
94 | * or dropped completely, | |
95 | * but let's get it working (again) first... | |
96 | */ | |
97 | ||
98 | static int init_baudrate (void) | |
99 | { | |
100 | DECLARE_GLOBAL_DATA_PTR; | |
101 | ||
102 | uchar tmp[64]; /* long enough for environment variables */ | |
103 | int i = getenv_r ("baudrate", tmp, sizeof (tmp)); | |
104 | ||
105 | gd->baudrate = (i > 0) | |
106 | ? (int) simple_strtoul (tmp, NULL, 10) | |
107 | : CONFIG_BAUDRATE; | |
108 | ||
109 | return (0); | |
110 | } | |
111 | ||
112 | static int display_banner (void) | |
113 | { | |
114 | ||
115 | printf ("\n\n%s\n\n", version_string); | |
116 | printf ("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n", | |
117 | _armboot_start, _armboot_end_data, _armboot_end); | |
118 | #ifdef CONFIG_MODEM_SUPPORT | |
119 | puts ("Modem Support enabled\n"); | |
120 | #endif | |
121 | #ifdef CONFIG_USE_IRQ | |
122 | printf ("IRQ Stack: %08lx\n", IRQ_STACK_START); | |
123 | printf ("FIQ Stack: %08lx\n", FIQ_STACK_START); | |
124 | #endif | |
125 | return (0); | |
126 | } | |
127 | ||
128 | /* | |
129 | * WARNING: this code looks "cleaner" than the PowerPC version, but | |
130 | * has the disadvantage that you either get nothing, or everything. | |
131 | * On PowerPC, you might see "DRAM: " before the system hangs - which | |
132 | * gives a simple yet clear indication which part of the | |
133 | * initialization if failing. | |
134 | */ | |
135 | static int display_dram_config (void) | |
136 | { | |
137 | DECLARE_GLOBAL_DATA_PTR; | |
138 | int i; | |
139 | ||
140 | puts ("DRAM Configuration:\n"); | |
141 | ||
142 | for(i=0; i<CONFIG_NR_DRAM_BANKS; i++) { | |
143 | printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start); | |
144 | print_size (gd->bd->bi_dram[i].size, "\n"); | |
145 | } | |
146 | ||
147 | return (0); | |
148 | } | |
149 | ||
150 | static void display_flash_config (ulong size) | |
151 | { | |
152 | puts ("Flash: "); | |
153 | print_size (size, "\n"); | |
154 | } | |
155 | ||
156 | ||
c609719b WD |
157 | /* |
158 | * Breath some life into the board... | |
159 | * | |
160 | * Initialize an SMC for serial comms, and carry out some hardware | |
161 | * tests. | |
162 | * | |
163 | * The first part of initialization is running from Flash memory; | |
164 | * its main purpose is to initialize the RAM so that we | |
165 | * can relocate the monitor code to RAM. | |
166 | */ | |
167 | ||
168 | /* | |
169 | * All attempts to come up with a "common" initialization sequence | |
170 | * that works for all boards and architectures failed: some of the | |
171 | * requirements are just _too_ different. To get rid of the resulting | |
172 | * mess of board dependend #ifdef'ed code we now make the whole | |
173 | * initialization sequence configurable to the user. | |
174 | * | |
175 | * The requirements for any new initalization function is simple: it | |
176 | * receives a pointer to the "global data" structure as it's only | |
177 | * argument, and returns an integer return code, where 0 means | |
178 | * "continue" and != 0 means "fatal error, hang the system". | |
179 | */ | |
180 | typedef int (init_fnc_t) (void); | |
181 | ||
182 | init_fnc_t *init_sequence[] = { | |
183 | cpu_init, /* basic cpu dependent setup */ | |
184 | board_init, /* basic board dependent setup */ | |
185 | interrupt_init, /* set up exceptions */ | |
186 | env_init, /* initialize environment */ | |
187 | init_baudrate, /* initialze baudrate settings */ | |
188 | serial_init, /* serial communications setup */ | |
699b13a6 | 189 | display_banner, /* say that we are here */ |
c609719b WD |
190 | dram_init, /* configure available RAM banks */ |
191 | display_dram_config, | |
1cb8e980 WD |
192 | #if defined(CONFIG_VCMA9) |
193 | checkboard, | |
194 | #endif | |
c609719b WD |
195 | NULL, |
196 | }; | |
197 | ||
198 | void start_armboot (void) | |
199 | { | |
200 | DECLARE_GLOBAL_DATA_PTR; | |
201 | ||
202 | ulong size; | |
203 | gd_t gd_data; | |
204 | bd_t bd_data; | |
205 | init_fnc_t **init_fnc_ptr; | |
3e38691e | 206 | char *s; |
6069ff26 | 207 | #if defined(CONFIG_VFD) |
c609719b WD |
208 | unsigned long addr; |
209 | #endif | |
210 | ||
211 | /* Pointer is writable since we allocated a register for it */ | |
212 | gd = &gd_data; | |
213 | memset (gd, 0, sizeof (gd_t)); | |
214 | gd->bd = &bd_data; | |
215 | memset (gd->bd, 0, sizeof (bd_t)); | |
216 | ||
3b57fe0a WD |
217 | monitor_flash_len = _armboot_end_data - _armboot_start; |
218 | ||
c609719b WD |
219 | for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { |
220 | if ((*init_fnc_ptr)() != 0) { | |
221 | hang (); | |
222 | } | |
223 | } | |
224 | ||
225 | /* configure available FLASH banks */ | |
226 | size = flash_init (); | |
227 | display_flash_config (size); | |
228 | ||
229 | #ifdef CONFIG_VFD | |
6069ff26 WD |
230 | # ifndef PAGE_SIZE |
231 | # define PAGE_SIZE 4096 | |
232 | # endif | |
c609719b WD |
233 | /* |
234 | * reserve memory for VFD display (always full pages) | |
235 | */ | |
236 | /* armboot_real_end is defined in the board-specific linker script */ | |
237 | addr = (_armboot_real_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); | |
238 | size = vfd_setmem (addr); | |
239 | gd->fb_base = addr; | |
240 | /* round to the next page boundary */ | |
241 | addr += size; | |
242 | addr = (addr + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); | |
243 | mem_malloc_init (addr); | |
244 | #else | |
245 | /* armboot_real_end is defined in the board-specific linker script */ | |
246 | mem_malloc_init (_armboot_real_end); | |
247 | #endif /* CONFIG_VFD */ | |
248 | ||
dc7c9a1a WD |
249 | #if (CONFIG_COMMANDS & CFG_CMD_NAND) |
250 | nand_init(); /* go init the NAND */ | |
251 | #endif | |
252 | ||
2abbe075 WD |
253 | #ifdef CONFIG_HAS_DATAFLASH |
254 | AT91F_DataflashInit(); | |
255 | dataflash_print_info(); | |
256 | #endif | |
257 | ||
6069ff26 WD |
258 | /* initialize environment */ |
259 | env_relocate (); | |
260 | ||
c609719b WD |
261 | #ifdef CONFIG_VFD |
262 | /* must do this after the framebuffer is allocated */ | |
263 | drv_vfd_init(); | |
264 | #endif | |
c609719b WD |
265 | |
266 | /* IP Address */ | |
267 | bd_data.bi_ip_addr = getenv_IPaddr ("ipaddr"); | |
268 | ||
269 | /* MAC Address */ | |
270 | { | |
271 | int i; | |
272 | ulong reg; | |
273 | char *s, *e; | |
274 | uchar tmp[64]; | |
275 | ||
276 | i = getenv_r ("ethaddr", tmp, sizeof (tmp)); | |
277 | s = (i > 0) ? tmp : NULL; | |
278 | ||
279 | for (reg = 0; reg < 6; ++reg) { | |
280 | bd_data.bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0; | |
281 | if (s) | |
282 | s = (*e) ? e + 1 : e; | |
283 | } | |
284 | } | |
285 | ||
286 | #if defined(CONFIG_MISC_INIT_R) | |
287 | /* miscellaneous platform dependent initialisations */ | |
288 | misc_init_r (); | |
289 | #endif | |
290 | ||
291 | /* enable exceptions */ | |
292 | enable_interrupts (); | |
293 | ||
294 | #ifdef CONFIG_DRIVER_CS8900 | |
6069ff26 | 295 | cs8900_get_enetaddr (gd->bd->bi_enetaddr); |
c609719b WD |
296 | #endif |
297 | ||
45219c46 WD |
298 | #ifdef CONFIG_DRIVER_LAN91C96 |
299 | if (getenv ("ethaddr")) { | |
300 | smc_set_mac_addr(gd->bd->bi_enetaddr); | |
301 | } | |
302 | /* eth_hw_init(); */ | |
303 | #endif /* CONFIG_DRIVER_LAN91C96 */ | |
304 | ||
3e38691e WD |
305 | /* Initialize from environment */ |
306 | if ((s = getenv ("loadaddr")) != NULL) { | |
307 | load_addr = simple_strtoul (s, NULL, 16); | |
308 | } | |
309 | #if (CONFIG_COMMANDS & CFG_CMD_NET) | |
310 | if ((s = getenv ("bootfile")) != NULL) { | |
311 | copy_filename (BootFile, s, sizeof (BootFile)); | |
312 | } | |
313 | #endif /* CFG_CMD_NET */ | |
314 | ||
c609719b WD |
315 | #ifdef BOARD_POST_INIT |
316 | board_post_init (); | |
317 | #endif | |
318 | ||
319 | /* main_loop() can return to retry autoboot, if so just run it again. */ | |
320 | for (;;) { | |
321 | main_loop (); | |
322 | } | |
323 | ||
324 | /* NOTREACHED - no way out of command loop except booting */ | |
325 | } | |
326 | ||
327 | void hang (void) | |
328 | { | |
329 | puts ("### ERROR ### Please RESET the board ###\n"); | |
330 | for (;;); | |
331 | } | |
332 | ||
333 | #ifdef CONFIG_MODEM_SUPPORT | |
334 | /* called from main loop (common/main.c) */ | |
335 | extern void dbg(const char *fmt, ...); | |
336 | int mdm_init (void) | |
337 | { | |
338 | char env_str[16]; | |
339 | char *init_str; | |
340 | int i; | |
341 | extern char console_buffer[]; | |
342 | static inline void mdm_readline(char *buf, int bufsiz); | |
343 | extern void enable_putc(void); | |
344 | extern int hwflow_onoff(int); | |
345 | ||
346 | enable_putc(); /* enable serial_putc() */ | |
347 | ||
348 | #ifdef CONFIG_HWFLOW | |
349 | init_str = getenv("mdm_flow_control"); | |
350 | if (init_str && (strcmp(init_str, "rts/cts") == 0)) | |
351 | hwflow_onoff (1); | |
352 | else | |
353 | hwflow_onoff(-1); | |
354 | #endif | |
355 | ||
356 | for (i = 1;;i++) { | |
357 | sprintf(env_str, "mdm_init%d", i); | |
358 | if ((init_str = getenv(env_str)) != NULL) { | |
359 | serial_puts(init_str); | |
360 | serial_puts("\n"); | |
361 | for(;;) { | |
362 | mdm_readline(console_buffer, CFG_CBSIZE); | |
363 | dbg("ini%d: [%s]", i, console_buffer); | |
364 | ||
365 | if ((strcmp(console_buffer, "OK") == 0) || | |
366 | (strcmp(console_buffer, "ERROR") == 0)) { | |
367 | dbg("ini%d: cmd done", i); | |
368 | break; | |
369 | } else /* in case we are originating call ... */ | |
370 | if (strncmp(console_buffer, "CONNECT", 7) == 0) { | |
371 | dbg("ini%d: connect", i); | |
372 | return 0; | |
373 | } | |
374 | } | |
375 | } else | |
376 | break; /* no init string - stop modem init */ | |
377 | ||
378 | udelay(100000); | |
379 | } | |
380 | ||
381 | udelay(100000); | |
382 | ||
383 | /* final stage - wait for connect */ | |
384 | for(;i > 1;) { /* if 'i' > 1 - wait for connection | |
385 | message from modem */ | |
386 | mdm_readline(console_buffer, CFG_CBSIZE); | |
387 | dbg("ini_f: [%s]", console_buffer); | |
388 | if (strncmp(console_buffer, "CONNECT", 7) == 0) { | |
389 | dbg("ini_f: connected"); | |
390 | return 0; | |
391 | } | |
392 | } | |
393 | ||
394 | return 0; | |
395 | } | |
396 | ||
397 | /* 'inline' - We have to do it fast */ | |
398 | static inline void mdm_readline(char *buf, int bufsiz) | |
399 | { | |
400 | char c; | |
401 | char *p; | |
402 | int n; | |
403 | ||
404 | n = 0; | |
405 | p = buf; | |
406 | for(;;) { | |
407 | c = serial_getc(); | |
408 | ||
409 | /* dbg("(%c)", c); */ | |
410 | ||
411 | switch(c) { | |
412 | case '\r': | |
413 | break; | |
414 | case '\n': | |
415 | *p = '\0'; | |
416 | return; | |
417 | ||
418 | default: | |
419 | if(n++ > bufsiz) { | |
420 | *p = '\0'; | |
421 | return; /* sanity check */ | |
422 | } | |
423 | *p = c; | |
424 | p++; | |
425 | break; | |
426 | } | |
427 | } | |
428 | } | |
429 | #endif /* CONFIG_MODEM_SUPPORT */ |