122723828SAlexey Brodkin /*
222723828SAlexey Brodkin * Copyright (C) 2013-2014 Synopsys, Inc. All rights reserved.
322723828SAlexey Brodkin *
422723828SAlexey Brodkin * SPDX-License-Identifier: GPL-2.0+
522723828SAlexey Brodkin */
622723828SAlexey Brodkin
722723828SAlexey Brodkin #include <common.h>
822723828SAlexey Brodkin
922723828SAlexey Brodkin DECLARE_GLOBAL_DATA_PTR;
1022723828SAlexey Brodkin
get_sp(void)1122723828SAlexey Brodkin static ulong get_sp(void)
1222723828SAlexey Brodkin {
1322723828SAlexey Brodkin ulong ret;
1422723828SAlexey Brodkin
1522723828SAlexey Brodkin asm("mov %0, sp" : "=r"(ret) : );
1622723828SAlexey Brodkin return ret;
1722723828SAlexey Brodkin }
1822723828SAlexey Brodkin
arch_lmb_reserve(struct lmb * lmb)1922723828SAlexey Brodkin void arch_lmb_reserve(struct lmb *lmb)
2022723828SAlexey Brodkin {
2122723828SAlexey Brodkin ulong sp;
2222723828SAlexey Brodkin
2322723828SAlexey Brodkin /*
2422723828SAlexey Brodkin * Booting a (Linux) kernel image
2522723828SAlexey Brodkin *
2622723828SAlexey Brodkin * Allocate space for command line and board info - the
2722723828SAlexey Brodkin * address should be as high as possible within the reach of
2822723828SAlexey Brodkin * the kernel (see CONFIG_SYS_BOOTMAPSZ settings), but in unused
2922723828SAlexey Brodkin * memory, which means far enough below the current stack
3022723828SAlexey Brodkin * pointer.
3122723828SAlexey Brodkin */
3222723828SAlexey Brodkin sp = get_sp();
3322723828SAlexey Brodkin debug("## Current stack ends at 0x%08lx ", sp);
3422723828SAlexey Brodkin
3522723828SAlexey Brodkin /* adjust sp by 4K to be safe */
3622723828SAlexey Brodkin sp -= 4096;
3722723828SAlexey Brodkin lmb_reserve(lmb, sp, (CONFIG_SYS_SDRAM_BASE + gd->ram_size - sp));
3822723828SAlexey Brodkin }
3922723828SAlexey Brodkin
cleanup_before_linux(void)4022723828SAlexey Brodkin static int cleanup_before_linux(void)
4122723828SAlexey Brodkin {
4222723828SAlexey Brodkin disable_interrupts();
4322723828SAlexey Brodkin flush_dcache_all();
4422723828SAlexey Brodkin invalidate_icache_all();
4522723828SAlexey Brodkin
4622723828SAlexey Brodkin return 0;
4722723828SAlexey Brodkin }
4822723828SAlexey Brodkin
4922723828SAlexey Brodkin /* Subcommand: PREP */
boot_prep_linux(bootm_headers_t * images)5022723828SAlexey Brodkin static void boot_prep_linux(bootm_headers_t *images)
5122723828SAlexey Brodkin {
5222723828SAlexey Brodkin if (image_setup_linux(images))
5322723828SAlexey Brodkin hang();
5422723828SAlexey Brodkin }
5522723828SAlexey Brodkin
smp_set_core_boot_addr(unsigned long addr,int corenr)568b2eb776SAlexey Brodkin __weak void smp_set_core_boot_addr(unsigned long addr, int corenr) {}
smp_kick_all_cpus(void)578b2eb776SAlexey Brodkin __weak void smp_kick_all_cpus(void) {}
588b2eb776SAlexey Brodkin
5922723828SAlexey Brodkin /* Subcommand: GO */
boot_jump_linux(bootm_headers_t * images,int flag)6022723828SAlexey Brodkin static void boot_jump_linux(bootm_headers_t *images, int flag)
6122723828SAlexey Brodkin {
6222723828SAlexey Brodkin void (*kernel_entry)(int zero, int arch, uint params);
6322723828SAlexey Brodkin unsigned int r0, r2;
6422723828SAlexey Brodkin int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
6522723828SAlexey Brodkin
6622723828SAlexey Brodkin kernel_entry = (void (*)(int, int, uint))images->ep;
6722723828SAlexey Brodkin
6822723828SAlexey Brodkin debug("## Transferring control to Linux (at address %08lx)...\n",
6922723828SAlexey Brodkin (ulong) kernel_entry);
7022723828SAlexey Brodkin bootstage_mark(BOOTSTAGE_ID_RUN_OS);
7122723828SAlexey Brodkin
7222723828SAlexey Brodkin printf("\nStarting kernel ...%s\n\n", fake ?
7322723828SAlexey Brodkin "(fake run for tracing)" : "");
7422723828SAlexey Brodkin bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
7522723828SAlexey Brodkin
7622723828SAlexey Brodkin cleanup_before_linux();
7722723828SAlexey Brodkin
7822723828SAlexey Brodkin if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
7922723828SAlexey Brodkin r0 = 2;
8022723828SAlexey Brodkin r2 = (unsigned int)images->ft_addr;
8122723828SAlexey Brodkin } else {
8222723828SAlexey Brodkin r0 = 1;
83*00caae6dSSimon Glass r2 = (unsigned int)env_get("bootargs");
8422723828SAlexey Brodkin }
8522723828SAlexey Brodkin
868b2eb776SAlexey Brodkin smp_set_core_boot_addr((unsigned long)kernel_entry, -1);
878b2eb776SAlexey Brodkin smp_kick_all_cpus();
888b2eb776SAlexey Brodkin
8922723828SAlexey Brodkin if (!fake)
9022723828SAlexey Brodkin kernel_entry(r0, 0, r2);
9122723828SAlexey Brodkin }
9222723828SAlexey Brodkin
do_bootm_linux(int flag,int argc,char * argv[],bootm_headers_t * images)9322723828SAlexey Brodkin int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
9422723828SAlexey Brodkin {
9522723828SAlexey Brodkin /* No need for those on ARC */
9622723828SAlexey Brodkin if ((flag & BOOTM_STATE_OS_BD_T) || (flag & BOOTM_STATE_OS_CMDLINE))
9722723828SAlexey Brodkin return -1;
9822723828SAlexey Brodkin
9922723828SAlexey Brodkin if (flag & BOOTM_STATE_OS_PREP) {
10022723828SAlexey Brodkin boot_prep_linux(images);
10122723828SAlexey Brodkin return 0;
10222723828SAlexey Brodkin }
10322723828SAlexey Brodkin
10422723828SAlexey Brodkin if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
10522723828SAlexey Brodkin boot_jump_linux(images, flag);
10622723828SAlexey Brodkin return 0;
10722723828SAlexey Brodkin }
10822723828SAlexey Brodkin
10922723828SAlexey Brodkin boot_prep_linux(images);
11022723828SAlexey Brodkin boot_jump_linux(images, flag);
11122723828SAlexey Brodkin return 0;
11222723828SAlexey Brodkin }
113