blob: b6b5cdb762f2865c877e34bde0dd0be50d6a4007 [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
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
35const char version_string[] =
36 U_BOOT_VERSION" (" __DATE__ " - " __TIME__ ")";
37
38#ifdef CONFIG_DRIVER_CS8900
39extern void cs8900_get_enetaddr (uchar * addr);
40#endif
41
42/*
43 * Begin and End of memory area for malloc(), and current "brk"
44 */
45static ulong mem_malloc_start = 0;
46static ulong mem_malloc_end = 0;
47static ulong mem_malloc_brk = 0;
48
wdenk9dd2b882002-12-03 21:28:10 +000049#if !defined(CONFIG_MODEM_SUPPORT)
50static
51#endif
52void mem_malloc_init (ulong dest_addr)
wdenkc6097192002-11-03 00:24:07 +000053{
54 mem_malloc_start = dest_addr;
wdenk699b13a2002-11-03 18:03:52 +000055 mem_malloc_end = dest_addr + CFG_MALLOC_LEN;
wdenkc6097192002-11-03 00:24:07 +000056 mem_malloc_brk = mem_malloc_start;
57
58 memset ((void *) mem_malloc_start, 0,
59 mem_malloc_end - mem_malloc_start);
60}
61
62void *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
83static 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
97static 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 */
120static 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
135static 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 */
166typedef int (init_fnc_t) (void);
167
168init_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 */
wdenk699b13a2002-11-03 18:03:52 +0000175 display_banner, /* say that we are here */
wdenkc6097192002-11-03 00:24:07 +0000176 dram_init, /* configure available RAM banks */
177 display_dram_config,
178
179 NULL,
180};
181
182void 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;
wdenk9dd2b882002-12-03 21:28:10 +0000190#if defined(CONFIG_VFD) && !defined(CONFIG_MODEM_SUPPORT)
wdenkc6097192002-11-03 00:24:07 +0000191 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
wdenk9dd2b882002-12-03 21:28:10 +0000211#ifndef CONFIG_MODEM_SUPPORT
wdenkc6097192002-11-03 00:24:07 +0000212#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);
wdenk9dd2b882002-12-03 21:28:10 +0000226#endif /* CONFIG_MODEM_SUPPORT */
wdenkc6097192002-11-03 00:24:07 +0000227#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
wdenk9dd2b882002-12-03 21:28:10 +0000233#ifndef CONFIG_MODEM_SUPPORT
wdenkc6097192002-11-03 00:24:07 +0000234 /* must do this after the framebuffer is allocated */
235 drv_vfd_init();
wdenk9dd2b882002-12-03 21:28:10 +0000236#endif /* CONFIG_MODEM_SUPPORT */
wdenkc6097192002-11-03 00:24:07 +0000237#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
287void 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) */
295extern void dbg(const char *fmt, ...);
296int 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 */
358static 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 */