1ea0364f1SPeter Tyser /*
2ea0364f1SPeter Tyser * (C) Copyright 2003
3ea0364f1SPeter Tyser * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4ea0364f1SPeter Tyser *
51a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+
6ea0364f1SPeter Tyser */
7ea0364f1SPeter Tyser
8ea0364f1SPeter Tyser #include <common.h>
9ea0364f1SPeter Tyser #include <command.h>
10ea0364f1SPeter Tyser #include <image.h>
11ea0364f1SPeter Tyser #include <u-boot/zlib.h>
12ea0364f1SPeter Tyser #include <bzlib.h>
13ea0364f1SPeter Tyser #include <watchdog.h>
14ea0364f1SPeter Tyser #include <environment.h>
15ea0364f1SPeter Tyser #include <asm/byteorder.h>
16ea0364f1SPeter Tyser #ifdef CONFIG_SHOW_BOOT_PROGRESS
17ea0364f1SPeter Tyser # include <status_led.h>
18ea0364f1SPeter Tyser #endif
19ea0364f1SPeter Tyser
20ea0364f1SPeter Tyser DECLARE_GLOBAL_DATA_PTR;
21ea0364f1SPeter Tyser
22ea0364f1SPeter Tyser #define PHYSADDR(x) x
23ea0364f1SPeter Tyser
24ea0364f1SPeter Tyser #define LINUX_MAX_ENVS 256
25ea0364f1SPeter Tyser #define LINUX_MAX_ARGS 256
26ea0364f1SPeter Tyser
27ea0364f1SPeter Tyser static ulong get_sp (void);
28ea0364f1SPeter Tyser static void set_clocks_in_mhz (bd_t *kbd);
29ea0364f1SPeter Tyser
arch_lmb_reserve(struct lmb * lmb)30ea0364f1SPeter Tyser void arch_lmb_reserve(struct lmb *lmb)
31ea0364f1SPeter Tyser {
32ea0364f1SPeter Tyser ulong sp;
33ea0364f1SPeter Tyser
34ea0364f1SPeter Tyser /*
35ea0364f1SPeter Tyser * Booting a (Linux) kernel image
36ea0364f1SPeter Tyser *
37ea0364f1SPeter Tyser * Allocate space for command line and board info - the
38ea0364f1SPeter Tyser * address should be as high as possible within the reach of
39ea0364f1SPeter Tyser * the kernel (see CONFIG_SYS_BOOTMAPSZ settings), but in unused
40ea0364f1SPeter Tyser * memory, which means far enough below the current stack
41ea0364f1SPeter Tyser * pointer.
42ea0364f1SPeter Tyser */
43ea0364f1SPeter Tyser sp = get_sp();
44ea0364f1SPeter Tyser debug ("## Current stack ends at 0x%08lx ", sp);
45ea0364f1SPeter Tyser
46ea0364f1SPeter Tyser /* adjust sp by 1K to be safe */
47ea0364f1SPeter Tyser sp -= 1024;
48ea0364f1SPeter Tyser lmb_reserve(lmb, sp, (CONFIG_SYS_SDRAM_BASE + gd->ram_size - sp));
49ea0364f1SPeter Tyser }
50ea0364f1SPeter Tyser
do_bootm_linux(int flag,int argc,char * const argv[],bootm_headers_t * images)5154841ab5SWolfgang Denk int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *images)
52ea0364f1SPeter Tyser {
53ea0364f1SPeter Tyser int ret;
54ea0364f1SPeter Tyser bd_t *kbd;
55ea0364f1SPeter Tyser void (*kernel) (bd_t *, ulong, ulong, ulong, ulong);
56ea0364f1SPeter Tyser struct lmb *lmb = &images->lmb;
57ea0364f1SPeter Tyser
582cb0e55aSAndreas Bießmann /*
592cb0e55aSAndreas Bießmann * allow the PREP bootm subcommand, it is required for bootm to work
602cb0e55aSAndreas Bießmann */
612cb0e55aSAndreas Bießmann if (flag & BOOTM_STATE_OS_PREP)
622cb0e55aSAndreas Bießmann return 0;
632cb0e55aSAndreas Bießmann
64ea0364f1SPeter Tyser if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
65ea0364f1SPeter Tyser return 1;
66ea0364f1SPeter Tyser
67ea0364f1SPeter Tyser /* allocate space for kernel copy of board info */
68590d3cacSGrant Likely ret = boot_get_kbd (lmb, &kbd);
69ea0364f1SPeter Tyser if (ret) {
70ea0364f1SPeter Tyser puts("ERROR with allocation of kernel bd\n");
71ea0364f1SPeter Tyser goto error;
72ea0364f1SPeter Tyser }
73ea0364f1SPeter Tyser set_clocks_in_mhz(kbd);
74ea0364f1SPeter Tyser
7524507cf5SSimon Glass ret = image_setup_linux(images);
76ea0364f1SPeter Tyser if (ret)
77ea0364f1SPeter Tyser goto error;
78ea0364f1SPeter Tyser
7924507cf5SSimon Glass kernel = (void (*)(bd_t *, ulong, ulong, ulong, ulong))images->ep;
8024507cf5SSimon Glass
81ea0364f1SPeter Tyser debug("## Transferring control to Linux (at address %08lx) ...\n",
82ea0364f1SPeter Tyser (ulong) kernel);
83ea0364f1SPeter Tyser
84770605e4SSimon Glass bootstage_mark(BOOTSTAGE_ID_RUN_OS);
85ea0364f1SPeter Tyser
86ea0364f1SPeter Tyser /*
87ea0364f1SPeter Tyser * Linux Kernel Parameters (passing board info data):
88ea0364f1SPeter Tyser * sp+00: Ignore, side effect of using jsr to jump to kernel
89ea0364f1SPeter Tyser * sp+04: ptr to board info data
90ea0364f1SPeter Tyser * sp+08: initrd_start or 0 if no initrd
91ea0364f1SPeter Tyser * sp+12: initrd_end - unused if initrd_start is 0
92ea0364f1SPeter Tyser * sp+16: Start of command line string
93ea0364f1SPeter Tyser * sp+20: End of command line string
94ea0364f1SPeter Tyser */
95ddc94378SSimon Glass (*kernel)(kbd, images->initrd_start, images->initrd_end,
96ddc94378SSimon Glass images->cmdline_start, images->cmdline_end);
97ea0364f1SPeter Tyser /* does not return */
98ea0364f1SPeter Tyser error:
99ea0364f1SPeter Tyser return 1;
100ea0364f1SPeter Tyser }
101ea0364f1SPeter Tyser
get_sp(void)102ea0364f1SPeter Tyser static ulong get_sp (void)
103ea0364f1SPeter Tyser {
104ea0364f1SPeter Tyser ulong sp;
105ea0364f1SPeter Tyser
106ea0364f1SPeter Tyser asm("movel %%a7, %%d0\n"
107ea0364f1SPeter Tyser "movel %%d0, %0\n": "=d"(sp): :"%d0");
108ea0364f1SPeter Tyser
109ea0364f1SPeter Tyser return sp;
110ea0364f1SPeter Tyser }
111ea0364f1SPeter Tyser
set_clocks_in_mhz(bd_t * kbd)112ea0364f1SPeter Tyser static void set_clocks_in_mhz (bd_t *kbd)
113ea0364f1SPeter Tyser {
114ea0364f1SPeter Tyser char *s;
115ea0364f1SPeter Tyser
116*00caae6dSSimon Glass s = env_get("clocks_in_mhz");
117*00caae6dSSimon Glass if (s) {
118ea0364f1SPeter Tyser /* convert all clock information to MHz */
119ea0364f1SPeter Tyser kbd->bi_intfreq /= 1000000L;
120ea0364f1SPeter Tyser kbd->bi_busfreq /= 1000000L;
121ea0364f1SPeter Tyser }
122ea0364f1SPeter Tyser }
123