Add more stock U-Boot images
[oweals/u-boot_mod.git] / u-boot / lib_mips / board.c
1 /*
2  * (C) Copyright 2003
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 #include <common.h>
25 #include <command.h>
26 #include <asm/mipsregs.h>
27 #include <asm/addrspace.h>
28 #include <malloc.h>
29 #include <devices.h>
30 #include <version.h>
31 #include <net.h>
32 #include <environment.h>
33
34 DECLARE_GLOBAL_DATA_PTR;
35
36 /*#define BOARD_DEBUG*/
37
38 #if (((CFG_ENV_ADDR + CFG_ENV_SIZE) < CFG_MONITOR_BASE)      ||\
39      (CFG_ENV_ADDR >= (CFG_MONITOR_BASE + CFG_MONITOR_LEN))) ||\
40      defined(CFG_ENV_IS_IN_NVRAM)
41         #define TOTAL_MALLOC_LEN        (CFG_MALLOC_LEN + CFG_ENV_SIZE)
42 #else
43         #define TOTAL_MALLOC_LEN        CFG_MALLOC_LEN
44 #endif
45
46 extern ulong uboot_end_data;
47 extern ulong uboot_end;
48
49 ulong monitor_flash_len;
50
51 const char version_string[] = U_BOOT_VERSION;
52
53 /* Begin and end of memory area for malloc(), and current "brk" */
54 static ulong mem_malloc_start;
55 static ulong mem_malloc_end;
56 static ulong mem_malloc_brk;
57
58 /* The Malloc area is immediately below the monitor copy in DRAM */
59 static void mem_malloc_init(void)
60 {
61         ulong dest_addr = CFG_MONITOR_BASE + gd->reloc_off;
62
63         mem_malloc_end = dest_addr;
64         mem_malloc_start = dest_addr - TOTAL_MALLOC_LEN;
65         mem_malloc_brk = mem_malloc_start;
66
67         memset((void *)mem_malloc_start,
68                 0, mem_malloc_end - mem_malloc_start);
69 }
70
71 void *sbrk(ptrdiff_t increment)
72 {
73         ulong old = mem_malloc_brk;
74         ulong new = old + increment;
75
76         if ((new < mem_malloc_start) || (new > mem_malloc_end)) {
77                 printf_err("sbrk: out of memory "
78                         "(%d requested > %d available)\n",
79                         increment, mem_malloc_end - old);
80
81                 return (void*)MORECORE_FAILURE;
82         }
83
84         mem_malloc_brk = new;
85
86         return (void *)old;
87 }
88
89 static int display_banner(void)
90 {
91         puts("\n");
92
93 #if defined(CONFIG_SKIP_LOWLEVEL_INIT)
94         puts("\n***************************************"
95              "\n*                                     *"
96              "\n*             RAM VERSION             *"
97              "\n*                                     *");
98 #endif
99
100         printf("\n***************************************"
101                "\n*     %s     *"
102                "\n*          Build: "
103                MK_STR(CONFIG_BUILD_DATE_UTC) "          *"
104                "\n***************************************\n\n",
105                version_string);
106
107         return 0;
108 }
109
110 static int baudrate_init(void)
111 {
112         char *s;
113
114         if ((s = getenv("baudrate")) != NULL)
115                 gd->baudrate = simple_strtoul(s, NULL, 10);
116         else
117                 gd->baudrate = CONFIG_BAUDRATE;
118
119         return 0;
120 }
121
122 #if !defined(COMPRESSED_UBOOT)
123 static int init_func_ram(void)
124 {
125         if ((gd->ram_size = dram_init()) > 0)
126                 return 0;
127
128         printf_err("on RAM initialization!\n");
129         return 1;
130 }
131 #endif
132
133 /*
134  * Breath some life into the board...
135  *
136  * The first part of initialization is running from Flash memory;
137  * its main purpose is to initialize the RAM so that we
138  * can relocate the monitor code to RAM.
139  */
140
141 /*
142  * All attempts to come up with a "common" initialization sequence
143  * that works for all boards and architectures failed: some of the
144  * requirements are just _too_ different. To get rid of the resulting
145  * mess of board dependend #ifdef'ed code we now make the whole
146  * initialization sequence configurable to the user.
147  *
148  * The requirements for any new initalization function is simple: it
149  * receives a pointer to the "global data" structure as it's only
150  * argument, and returns an integer return code, where 0 means
151  * "continue" and != 0 means "fatal error, hang the system".
152  */
153 typedef int(init_fnc_t)(void);
154
155 #if !defined(COMPRESSED_UBOOT)
156 init_fnc_t *init_sequence[] = { timer_init,
157                                 env_init,
158                                 baudrate_init,
159                                 serial_init,
160                                 console_init_f,
161                                 display_banner,
162                                 init_func_ram,
163                                 NULL, };
164 #else
165 init_fnc_t *init_sequence[] = { timer_init,
166                                 env_init,
167                                 baudrate_init,
168                                 serial_init,
169                                 console_init_f,
170                                 display_banner,
171                                 NULL, };
172 #endif
173
174 /*
175  *
176  * BOARD INITIALIZATION
177  *
178  */
179 void board_init_f(ulong bootflag)
180 {
181         ulong len = (ulong)&uboot_end - CFG_MONITOR_BASE;
182         init_fnc_t **init_fnc_ptr;
183         ulong addr, addr_sp, *s;
184         gd_t gd_data, *id;
185         bd_t *bd;
186
187         /* Pointer is writable since we allocated a register for it */
188         gd = &gd_data;
189
190         /* Compiler optimization barrier needed for GCC >= 3.4 */
191         __asm__ __volatile__("": : :"memory");
192
193         memset((void *)gd, 0, sizeof(gd_t));
194
195         /* Loop trough init_sequence */
196         for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
197                 if ((*init_fnc_ptr)() != 0)
198                         hang();
199         }
200
201 #if defined(COMPRESSED_UBOOT)
202         gd->ram_size = bootflag;
203 #endif
204
205         /*
206          * Now that we have DRAM mapped and working, we can
207          * relocate the code and continue running from DRAM
208          */
209         addr = CFG_SDRAM_BASE + gd->ram_size;
210
211         /*
212          * We can reserve some RAM "on top" here,
213          * round down to next 4 kB limit
214          */
215         addr &= ~(4096 - 1);
216
217 #if defined(BOARD_DEBUG)
218         printf("Top of RAM usable for U-Boot at: %08lX\n", addr);
219 #endif
220
221         /*
222          * Reserve memory for U-Boot code, data & bss,
223          * round down to next 16 kB limit
224          */
225         addr -= len;
226         addr &= ~(16 * 1024 - 1);
227
228 #if defined(BOARD_DEBUG)
229         printf("Reserving %ldk for U-Boot at: %08lX\n", len >> 10, addr);
230 #endif
231
232         /* Reserve memory for malloc() arena */
233         addr_sp = addr - TOTAL_MALLOC_LEN;
234
235 #if defined(BOARD_DEBUG)
236         printf("Reserving %dk for malloc() at: %08lX\n",
237                 TOTAL_MALLOC_LEN >> 10, addr_sp);
238 #endif
239
240         /*
241          * (permanently) allocate a Board Info struct
242          * and a permanent copy of the "global" data
243          */
244         addr_sp -= sizeof(bd_t);
245         bd = (bd_t *)addr_sp;
246         gd->bd = bd;
247
248 #if defined(BOARD_DEBUG)
249         printf("Reserving %d Bytes for Board Info at: %08lX\n",
250                 sizeof(bd_t), addr_sp);
251 #endif
252
253         addr_sp -= sizeof(gd_t);
254         id = (gd_t *)addr_sp;
255
256 #if defined(BOARD_DEBUG)
257         printf("Reserving %d Bytes for Global Data at: %08lX\n",
258                 sizeof(gd_t), addr_sp);
259 #endif
260
261         /* Reserve memory for boot params */
262         addr_sp -= CFG_BOOTPARAMS_LEN;
263         bd->bi_boot_params = addr_sp;
264
265 #if defined(BOARD_DEBUG)
266         printf("Reserving %dk for boot params() at: %08lX\n",
267                 CFG_BOOTPARAMS_LEN >> 10, addr_sp);
268 #endif
269
270         /*
271          * Finally, we set up a new (bigger) stack
272          *
273          * Leave some safety gap for SP, force alignment on 16 byte boundary,
274          * clear initial stack frame
275          */
276         addr_sp -= 16;
277         addr_sp &= ~0xF;
278         s = (ulong *)addr_sp;
279         *s-- = 0;
280         *s-- = 0;
281         addr_sp = (ulong)s;
282
283 #if defined(BOARD_DEBUG)
284         printf("Stack Pointer at: %08lX\n", addr_sp);
285 #endif
286
287         /*
288          * Save local variables to board info struct:
289          * - start of DRAM memory
290          * - size  of DRAM memory in bytes
291          * - console baudrate
292          */
293         bd->bi_memstart = CFG_SDRAM_BASE;
294         bd->bi_memsize  = gd->ram_size;
295         bd->bi_baudrate = gd->baudrate;
296
297         memcpy(id, (void *)gd, sizeof(gd_t));
298
299         relocate_code(addr_sp, id, addr);
300         /* NOTREACHED - relocate_code() does not return */
301 }
302
303 /************************************************************************
304  *
305  * This is the next part if the initialization sequence: we are now
306  * running from RAM and have a "normal" C environment, i. e. global
307  * data can be written, BSS has been cleared, the stack size in not
308  * that critical any more, etc.
309  *
310  ************************************************************************
311  */
312 void board_init_r(gd_t *id, ulong dest_addr)
313 {
314         extern void malloc_bin_reloc(void);
315 #if !defined(CFG_ENV_IS_NOWHERE)
316         extern char *env_name_spec;
317 #endif
318         cmd_tbl_t *cmdtp;
319         char buf[20];
320         bd_t *bd;
321         char *s;
322         int i;
323
324         gd = id;
325
326         /* Tell others: relocation done */
327         gd->flags |= GD_FLG_RELOC;
328
329         /* bd -> board data */
330         bd = gd->bd;
331
332 #if defined(BOARD_DEBUG)
333         printf("Now running in RAM - U-Boot at: %08lX\n", dest_addr);
334 #endif
335
336         /* We need (half of the) main CPU clock for udelay */
337         bd->bi_cfg_hz = (u32)(main_cpu_clk() >> 1);
338
339         gd->reloc_off = dest_addr - CFG_MONITOR_BASE;
340
341         monitor_flash_len = (ulong)&uboot_end_data - dest_addr;
342
343         /* We have to relocate the command table manually */
344         for (cmdtp  = &__u_boot_cmd_start;
345              cmdtp != &__u_boot_cmd_end; cmdtp++) {
346                 ulong addr;
347
348                 addr = (ulong)(cmdtp->cmd) + gd->reloc_off;
349
350                 cmdtp->cmd =
351                         (int (*)(struct cmd_tbl_s *, int, int, char *[]))addr;
352
353                 addr = (ulong)(cmdtp->name) + gd->reloc_off;
354                 cmdtp->name = (char *)addr;
355
356                 if (cmdtp->usage) {
357                         addr = (ulong)(cmdtp->usage) + gd->reloc_off;
358                         cmdtp->usage = (char *)addr;
359                 }
360
361 #if defined(CFG_LONGHELP)
362                 if (cmdtp->help) {
363                         addr = (ulong)(cmdtp->help) + gd->reloc_off;
364                         cmdtp->help = (char *)addr;
365                 }
366 #endif
367         }
368
369         /* There are some other pointer constants we must deal with */
370 #if !defined(CFG_ENV_IS_NOWHERE)
371         env_name_spec += gd->reloc_off;
372 #endif
373
374         /* Configure available FLASH banks */
375         bd->bi_flashstart = CFG_FLASH_BASE;
376         bd->bi_flashsize  = flash_init();
377
378 #if (CFG_MONITOR_BASE == CFG_FLASH_BASE)
379         /* Reserved area for U-Boot */
380         bd->bi_flashoffset = monitor_flash_len;
381 #else
382         bd->bi_flashoffset = 0;
383 #endif
384
385         /* Initialize malloc() area */
386         mem_malloc_init();
387         malloc_bin_reloc();
388
389         /* Relocate environment function pointers etc. */
390         env_relocate();
391
392         /* Local device IP address */
393         bd->bi_ip_addr = getenv_IPaddr("ipaddr");
394
395 #if defined(CONFIG_PCI)
396         /* Do pci configuration */
397         pci_init();
398 #endif
399
400 #if defined(CONFIG_USB)
401         usb_init();
402 #endif
403
404         /* Leave this here (after malloc(), environment and PCI are working) */
405         /* Initialize devices */
406         devices_init();
407
408         jumptable_init();
409
410         /* Initialize the console (after the relocation and devices init) */
411         console_init_r();
412
413         /* Initialize from environment */
414         if ((s = getenv("loadaddr")) != NULL)
415                 load_addr = simple_strtoul(s, NULL, 16);
416
417 #if defined(CONFIG_CMD_NET)
418         if ((s = getenv("bootfile")) != NULL)
419                 copy_filename(BootFile, s, sizeof(BootFile));
420 #endif
421
422         /* Init MAC address in board data info */
423         if ((s = getenv("ethaddr")) != NULL && strlen(s) == 17) {
424                 /* Use the one from env */
425                 for (i = 0; i < 6; i++)
426                         bd->bi_enetaddr[i] =
427                                 simple_strtoul((char *)(s + (i * 3)), NULL, 16);
428         } else {
429                 /* Use the one provided by board func */
430                 macaddr_init(bd->bi_enetaddr);
431
432                 /* And revrite it to env variable */
433                 for (i = 0; i < 6; i++)
434                         sprintf((char *)(buf + (i * 3)), "%02X%c",
435                                 bd->bi_enetaddr[i], i < 5 ? ':' : '\0');
436
437                 setenv("ethaddr", buf);
438         }
439
440         /* Print some information about board */
441         print_board_info();
442
443 #if defined(CONFIG_CMD_NET)
444         all_led_on();
445         eth_initialize(gd->bd);
446         all_led_off();
447 #endif
448
449         /* main_loop() can return to retry autoboot, if so just run it again */
450         for (;;)
451                 main_loop();
452
453         /* NOTREACHED - no way out of command loop except booting */
454 }
455
456 void hang(void)
457 {
458         puts("## ERROR ##\n");
459
460         for (;;)
461                 ;
462 }