]>
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 | ||
34 | ||
35 | const char version_string[] = | |
36 | U_BOOT_VERSION" (" __DATE__ " - " __TIME__ ")"; | |
37 | ||
38 | #ifdef CONFIG_DRIVER_CS8900 | |
39 | extern void cs8900_get_enetaddr (uchar * addr); | |
40 | #endif | |
41 | ||
42 | /* | |
43 | * Begin and End of memory area for malloc(), and current "brk" | |
44 | */ | |
45 | static ulong mem_malloc_start = 0; | |
46 | static ulong mem_malloc_end = 0; | |
47 | static ulong mem_malloc_brk = 0; | |
48 | ||
a6c7ad2f WD |
49 | #if !defined(CONFIG_MODEM_SUPPORT) |
50 | static | |
51 | #endif | |
52 | void mem_malloc_init (ulong dest_addr) | |
c609719b WD |
53 | { |
54 | mem_malloc_start = dest_addr; | |
699b13a6 | 55 | mem_malloc_end = dest_addr + CFG_MALLOC_LEN; |
c609719b WD |
56 | mem_malloc_brk = mem_malloc_start; |
57 | ||
58 | memset ((void *) mem_malloc_start, 0, | |
59 | mem_malloc_end - mem_malloc_start); | |
60 | } | |
61 | ||
62 | void *sbrk (ptrdiff_t increment) | |
63 | { | |
64 | ulong old = mem_malloc_brk; | |
65 | ulong new = old + increment; | |
66 | ||
67 | if ((new < mem_malloc_start) || (new > mem_malloc_end)) { | |
68 | return (NULL); | |
69 | } | |
70 | mem_malloc_brk = new; | |
71 | ||
72 | return ((void *) old); | |
73 | } | |
74 | ||
75 | /************************************************************************ | |
76 | * Init Utilities * | |
77 | ************************************************************************ | |
78 | * Some of this code should be moved into the core functions, | |
79 | * or dropped completely, | |
80 | * but let's get it working (again) first... | |
81 | */ | |
82 | ||
83 | static int init_baudrate (void) | |
84 | { | |
85 | DECLARE_GLOBAL_DATA_PTR; | |
86 | ||
87 | uchar tmp[64]; /* long enough for environment variables */ | |
88 | int i = getenv_r ("baudrate", tmp, sizeof (tmp)); | |
89 | ||
90 | gd->baudrate = (i > 0) | |
91 | ? (int) simple_strtoul (tmp, NULL, 10) | |
92 | : CONFIG_BAUDRATE; | |
93 | ||
94 | return (0); | |
95 | } | |
96 | ||
97 | static int display_banner (void) | |
98 | { | |
99 | ||
100 | printf ("\n\n%s\n\n", version_string); | |
101 | printf ("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n", | |
102 | _armboot_start, _armboot_end_data, _armboot_end); | |
103 | #ifdef CONFIG_MODEM_SUPPORT | |
104 | puts ("Modem Support enabled\n"); | |
105 | #endif | |
106 | #ifdef CONFIG_USE_IRQ | |
107 | printf ("IRQ Stack: %08lx\n", IRQ_STACK_START); | |
108 | printf ("FIQ Stack: %08lx\n", FIQ_STACK_START); | |
109 | #endif | |
110 | return (0); | |
111 | } | |
112 | ||
113 | /* | |
114 | * WARNING: this code looks "cleaner" than the PowerPC version, but | |
115 | * has the disadvantage that you either get nothing, or everything. | |
116 | * On PowerPC, you might see "DRAM: " before the system hangs - which | |
117 | * gives a simple yet clear indication which part of the | |
118 | * initialization if failing. | |
119 | */ | |
120 | static int display_dram_config (void) | |
121 | { | |
122 | DECLARE_GLOBAL_DATA_PTR; | |
123 | int i; | |
124 | ||
125 | puts ("DRAM Configuration:\n"); | |
126 | ||
127 | for(i=0; i<CONFIG_NR_DRAM_BANKS; i++) { | |
128 | printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start); | |
129 | print_size (gd->bd->bi_dram[i].size, "\n"); | |
130 | } | |
131 | ||
132 | return (0); | |
133 | } | |
134 | ||
135 | static void display_flash_config (ulong size) | |
136 | { | |
137 | puts ("Flash: "); | |
138 | print_size (size, "\n"); | |
139 | } | |
140 | ||
141 | ||
142 | ||
143 | /* | |
144 | * Breath some life into the board... | |
145 | * | |
146 | * Initialize an SMC for serial comms, and carry out some hardware | |
147 | * tests. | |
148 | * | |
149 | * The first part of initialization is running from Flash memory; | |
150 | * its main purpose is to initialize the RAM so that we | |
151 | * can relocate the monitor code to RAM. | |
152 | */ | |
153 | ||
154 | /* | |
155 | * All attempts to come up with a "common" initialization sequence | |
156 | * that works for all boards and architectures failed: some of the | |
157 | * requirements are just _too_ different. To get rid of the resulting | |
158 | * mess of board dependend #ifdef'ed code we now make the whole | |
159 | * initialization sequence configurable to the user. | |
160 | * | |
161 | * The requirements for any new initalization function is simple: it | |
162 | * receives a pointer to the "global data" structure as it's only | |
163 | * argument, and returns an integer return code, where 0 means | |
164 | * "continue" and != 0 means "fatal error, hang the system". | |
165 | */ | |
166 | typedef int (init_fnc_t) (void); | |
167 | ||
168 | init_fnc_t *init_sequence[] = { | |
169 | cpu_init, /* basic cpu dependent setup */ | |
170 | board_init, /* basic board dependent setup */ | |
171 | interrupt_init, /* set up exceptions */ | |
172 | env_init, /* initialize environment */ | |
173 | init_baudrate, /* initialze baudrate settings */ | |
174 | serial_init, /* serial communications setup */ | |
699b13a6 | 175 | display_banner, /* say that we are here */ |
c609719b WD |
176 | dram_init, /* configure available RAM banks */ |
177 | display_dram_config, | |
178 | ||
179 | NULL, | |
180 | }; | |
181 | ||
182 | void start_armboot (void) | |
183 | { | |
184 | DECLARE_GLOBAL_DATA_PTR; | |
185 | ||
186 | ulong size; | |
187 | gd_t gd_data; | |
188 | bd_t bd_data; | |
189 | init_fnc_t **init_fnc_ptr; | |
a6c7ad2f | 190 | #if defined(CONFIG_VFD) && !defined(CONFIG_MODEM_SUPPORT) |
c609719b WD |
191 | unsigned long addr; |
192 | #endif | |
193 | ||
194 | /* Pointer is writable since we allocated a register for it */ | |
195 | gd = &gd_data; | |
196 | memset (gd, 0, sizeof (gd_t)); | |
197 | gd->bd = &bd_data; | |
198 | memset (gd->bd, 0, sizeof (bd_t)); | |
199 | ||
200 | for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { | |
201 | if ((*init_fnc_ptr)() != 0) { | |
202 | hang (); | |
203 | } | |
204 | } | |
205 | ||
206 | /* configure available FLASH banks */ | |
207 | size = flash_init (); | |
208 | display_flash_config (size); | |
209 | ||
210 | #ifdef CONFIG_VFD | |
a6c7ad2f | 211 | #ifndef CONFIG_MODEM_SUPPORT |
c609719b WD |
212 | #ifndef PAGE_SIZE |
213 | #define PAGE_SIZE 4096 | |
214 | #endif | |
215 | /* | |
216 | * reserve memory for VFD display (always full pages) | |
217 | */ | |
218 | /* armboot_real_end is defined in the board-specific linker script */ | |
219 | addr = (_armboot_real_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); | |
220 | size = vfd_setmem (addr); | |
221 | gd->fb_base = addr; | |
222 | /* round to the next page boundary */ | |
223 | addr += size; | |
224 | addr = (addr + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); | |
225 | mem_malloc_init (addr); | |
a6c7ad2f | 226 | #endif /* CONFIG_MODEM_SUPPORT */ |
c609719b WD |
227 | #else |
228 | /* armboot_real_end is defined in the board-specific linker script */ | |
229 | mem_malloc_init (_armboot_real_end); | |
230 | #endif /* CONFIG_VFD */ | |
231 | ||
232 | #ifdef CONFIG_VFD | |
a6c7ad2f | 233 | #ifndef CONFIG_MODEM_SUPPORT |
c609719b WD |
234 | /* must do this after the framebuffer is allocated */ |
235 | drv_vfd_init(); | |
a6c7ad2f | 236 | #endif /* CONFIG_MODEM_SUPPORT */ |
c609719b WD |
237 | #endif |
238 | /* initialize environment */ | |
239 | env_relocate (); | |
240 | ||
241 | /* IP Address */ | |
242 | bd_data.bi_ip_addr = getenv_IPaddr ("ipaddr"); | |
243 | ||
244 | /* MAC Address */ | |
245 | { | |
246 | int i; | |
247 | ulong reg; | |
248 | char *s, *e; | |
249 | uchar tmp[64]; | |
250 | ||
251 | i = getenv_r ("ethaddr", tmp, sizeof (tmp)); | |
252 | s = (i > 0) ? tmp : NULL; | |
253 | ||
254 | for (reg = 0; reg < 6; ++reg) { | |
255 | bd_data.bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0; | |
256 | if (s) | |
257 | s = (*e) ? e + 1 : e; | |
258 | } | |
259 | } | |
260 | ||
261 | #if defined(CONFIG_MISC_INIT_R) | |
262 | /* miscellaneous platform dependent initialisations */ | |
263 | misc_init_r (); | |
264 | #endif | |
265 | ||
266 | /* enable exceptions */ | |
267 | enable_interrupts (); | |
268 | ||
269 | #ifdef CONFIG_DRIVER_CS8900 | |
270 | if (!getenv ("ethaddr")) { | |
271 | cs8900_get_enetaddr (gd->bd->bi_enetaddr); | |
272 | } | |
273 | #endif | |
274 | ||
275 | #ifdef BOARD_POST_INIT | |
276 | board_post_init (); | |
277 | #endif | |
278 | ||
279 | /* main_loop() can return to retry autoboot, if so just run it again. */ | |
280 | for (;;) { | |
281 | main_loop (); | |
282 | } | |
283 | ||
284 | /* NOTREACHED - no way out of command loop except booting */ | |
285 | } | |
286 | ||
287 | void hang (void) | |
288 | { | |
289 | puts ("### ERROR ### Please RESET the board ###\n"); | |
290 | for (;;); | |
291 | } | |
292 | ||
293 | #ifdef CONFIG_MODEM_SUPPORT | |
294 | /* called from main loop (common/main.c) */ | |
295 | extern void dbg(const char *fmt, ...); | |
296 | int mdm_init (void) | |
297 | { | |
298 | char env_str[16]; | |
299 | char *init_str; | |
300 | int i; | |
301 | extern char console_buffer[]; | |
302 | static inline void mdm_readline(char *buf, int bufsiz); | |
303 | extern void enable_putc(void); | |
304 | extern int hwflow_onoff(int); | |
305 | ||
306 | enable_putc(); /* enable serial_putc() */ | |
307 | ||
308 | #ifdef CONFIG_HWFLOW | |
309 | init_str = getenv("mdm_flow_control"); | |
310 | if (init_str && (strcmp(init_str, "rts/cts") == 0)) | |
311 | hwflow_onoff (1); | |
312 | else | |
313 | hwflow_onoff(-1); | |
314 | #endif | |
315 | ||
316 | for (i = 1;;i++) { | |
317 | sprintf(env_str, "mdm_init%d", i); | |
318 | if ((init_str = getenv(env_str)) != NULL) { | |
319 | serial_puts(init_str); | |
320 | serial_puts("\n"); | |
321 | for(;;) { | |
322 | mdm_readline(console_buffer, CFG_CBSIZE); | |
323 | dbg("ini%d: [%s]", i, console_buffer); | |
324 | ||
325 | if ((strcmp(console_buffer, "OK") == 0) || | |
326 | (strcmp(console_buffer, "ERROR") == 0)) { | |
327 | dbg("ini%d: cmd done", i); | |
328 | break; | |
329 | } else /* in case we are originating call ... */ | |
330 | if (strncmp(console_buffer, "CONNECT", 7) == 0) { | |
331 | dbg("ini%d: connect", i); | |
332 | return 0; | |
333 | } | |
334 | } | |
335 | } else | |
336 | break; /* no init string - stop modem init */ | |
337 | ||
338 | udelay(100000); | |
339 | } | |
340 | ||
341 | udelay(100000); | |
342 | ||
343 | /* final stage - wait for connect */ | |
344 | for(;i > 1;) { /* if 'i' > 1 - wait for connection | |
345 | message from modem */ | |
346 | mdm_readline(console_buffer, CFG_CBSIZE); | |
347 | dbg("ini_f: [%s]", console_buffer); | |
348 | if (strncmp(console_buffer, "CONNECT", 7) == 0) { | |
349 | dbg("ini_f: connected"); | |
350 | return 0; | |
351 | } | |
352 | } | |
353 | ||
354 | return 0; | |
355 | } | |
356 | ||
357 | /* 'inline' - We have to do it fast */ | |
358 | static inline void mdm_readline(char *buf, int bufsiz) | |
359 | { | |
360 | char c; | |
361 | char *p; | |
362 | int n; | |
363 | ||
364 | n = 0; | |
365 | p = buf; | |
366 | for(;;) { | |
367 | c = serial_getc(); | |
368 | ||
369 | /* dbg("(%c)", c); */ | |
370 | ||
371 | switch(c) { | |
372 | case '\r': | |
373 | break; | |
374 | case '\n': | |
375 | *p = '\0'; | |
376 | return; | |
377 | ||
378 | default: | |
379 | if(n++ > bufsiz) { | |
380 | *p = '\0'; | |
381 | return; /* sanity check */ | |
382 | } | |
383 | *p = c; | |
384 | p++; | |
385 | break; | |
386 | } | |
387 | } | |
388 | } | |
389 | #endif /* CONFIG_MODEM_SUPPORT */ |