xref: /openbmc/u-boot/arch/arm/lib/crt0.S (revision 04a213b573c745c8999998712daf0d02115d10ad)
183d290c5STom Rini/* SPDX-License-Identifier: GPL-2.0+ */
2e05e5de7SAlbert ARIBAUD/*
3e05e5de7SAlbert ARIBAUD *  crt0 - C-runtime startup Code for ARM U-Boot
4e05e5de7SAlbert ARIBAUD *
5e05e5de7SAlbert ARIBAUD *  Copyright (c) 2012  Albert ARIBAUD <albert.u.boot@aribaud.net>
6e05e5de7SAlbert ARIBAUD */
7e05e5de7SAlbert ARIBAUD
8e05e5de7SAlbert ARIBAUD#include <config.h>
9e05e5de7SAlbert ARIBAUD#include <asm-offsets.h>
109c5feab7SBenoît Thébaudeau#include <linux/linkage.h>
11d22336aaSVikas Manocha#include <asm/assembler.h>
12e05e5de7SAlbert ARIBAUD
13e05e5de7SAlbert ARIBAUD/*
14e05e5de7SAlbert ARIBAUD * This file handles the target-independent stages of the U-Boot
15e05e5de7SAlbert ARIBAUD * start-up where a C runtime environment is needed. Its entry point
16e05e5de7SAlbert ARIBAUD * is _main and is branched into from the target's start.S file.
17e05e5de7SAlbert ARIBAUD *
18e05e5de7SAlbert ARIBAUD * _main execution sequence is:
19e05e5de7SAlbert ARIBAUD *
20e05e5de7SAlbert ARIBAUD * 1. Set up initial environment for calling board_init_f().
21e05e5de7SAlbert ARIBAUD *    This environment only provides a stack and a place to store
22e05e5de7SAlbert ARIBAUD *    the GD ('global data') structure, both located in some readily
23e05e5de7SAlbert ARIBAUD *    available RAM (SRAM, locked cache...). In this context, VARIABLE
24e05e5de7SAlbert ARIBAUD *    global data, initialized or not (BSS), are UNAVAILABLE; only
25ed64190fSSimon Glass *    CONSTANT initialized data are available. GD should be zeroed
26ed64190fSSimon Glass *    before board_init_f() is called.
27e05e5de7SAlbert ARIBAUD *
28e05e5de7SAlbert ARIBAUD * 2. Call board_init_f(). This function prepares the hardware for
29e05e5de7SAlbert ARIBAUD *    execution from system RAM (DRAM, DDR...) As system RAM may not
30e05e5de7SAlbert ARIBAUD *    be available yet, , board_init_f() must use the current GD to
31e05e5de7SAlbert ARIBAUD *    store any data which must be passed on to later stages. These
32e05e5de7SAlbert ARIBAUD *    data include the relocation destination, the future stack, and
33e05e5de7SAlbert ARIBAUD *    the future GD location.
34e05e5de7SAlbert ARIBAUD *
35e05e5de7SAlbert ARIBAUD * 3. Set up intermediate environment where the stack and GD are the
36e05e5de7SAlbert ARIBAUD *    ones allocated by board_init_f() in system RAM, but BSS and
37e05e5de7SAlbert ARIBAUD *    initialized non-const data are still not available.
38e05e5de7SAlbert ARIBAUD *
39ed64190fSSimon Glass * 4a.For U-Boot proper (not SPL), call relocate_code(). This function
40ed64190fSSimon Glass *    relocates U-Boot from its current location into the relocation
41ed64190fSSimon Glass *    destination computed by board_init_f().
42ed64190fSSimon Glass *
43ed64190fSSimon Glass * 4b.For SPL, board_init_f() just returns (to crt0). There is no
44ed64190fSSimon Glass *    code relocation in SPL.
45e05e5de7SAlbert ARIBAUD *
46e05e5de7SAlbert ARIBAUD * 5. Set up final environment for calling board_init_r(). This
47e05e5de7SAlbert ARIBAUD *    environment has BSS (initialized to 0), initialized non-const
48e05e5de7SAlbert ARIBAUD *    data (initialized to their intended value), and stack in system
49ed64190fSSimon Glass *    RAM (for SPL moving the stack and GD into RAM is optional - see
50ed64190fSSimon Glass *    CONFIG_SPL_STACK_R). GD has retained values set by board_init_f().
51e05e5de7SAlbert ARIBAUD *
52ed64190fSSimon Glass * 6. For U-Boot proper (not SPL), some CPUs have some work left to do
53ed64190fSSimon Glass *    at this point regarding memory, so call c_runtime_cpu_setup.
54ed64190fSSimon Glass *
55ed64190fSSimon Glass * 7. Branch to board_init_r().
56ed64190fSSimon Glass *
57ed64190fSSimon Glass * For more information see 'Board Initialisation Flow in README.
58e05e5de7SAlbert ARIBAUD */
59e05e5de7SAlbert ARIBAUD
60e05e5de7SAlbert ARIBAUD/*
61e05e5de7SAlbert ARIBAUD * entry point of crt0 sequence
62e05e5de7SAlbert ARIBAUD */
63e05e5de7SAlbert ARIBAUD
649c5feab7SBenoît ThébaudeauENTRY(_main)
65e05e5de7SAlbert ARIBAUD
66e05e5de7SAlbert ARIBAUD/*
67e05e5de7SAlbert ARIBAUD * Set up initial C runtime environment and call board_init_f(0).
68e05e5de7SAlbert ARIBAUD */
69e05e5de7SAlbert ARIBAUD
7066f30bf9SBenoît Thébaudeau#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
71c62c1b3cSVikas Manocha	ldr	r0, =(CONFIG_SPL_STACK)
72e05e5de7SAlbert ARIBAUD#else
73c62c1b3cSVikas Manocha	ldr	r0, =(CONFIG_SYS_INIT_SP_ADDR)
74e05e5de7SAlbert ARIBAUD#endif
75c62c1b3cSVikas Manocha	bic	r0, r0, #7	/* 8-byte alignment for ABI compliance */
76c62c1b3cSVikas Manocha	mov	sp, r0
77ecc30663SAlbert ARIBAUD	bl	board_init_f_alloc_reserve
785ba534d2SSimon Glass	mov	sp, r0
79adc421e4SAlbert ARIBAUD	/* set up gd here, outside any C code */
80adc421e4SAlbert ARIBAUD	mov	r9, r0
81ecc30663SAlbert ARIBAUD	bl	board_init_f_init_reserve
825ba534d2SSimon Glass
83e05e5de7SAlbert ARIBAUD	mov	r0, #0
84e05e5de7SAlbert ARIBAUD	bl	board_init_f
85e05e5de7SAlbert ARIBAUD
860d1d4e81SChia-Wei, Wang#if (defined(CONFIG_SPL_BUILD) && !defined(CONFIG_TPL_BUILD) && !defined(CONFIG_SPL_SKIP_RELOCATE)) || \
870d1d4e81SChia-Wei, Wang	!defined(CONFIG_SPL_BUILD)
88e05e5de7SAlbert ARIBAUD/*
89e05e5de7SAlbert ARIBAUD * Set up intermediate environment (new sp and gd) and call
905c6db120SBenoît Thébaudeau * relocate_code(addr_moni). Trick here is that we'll return
915c6db120SBenoît Thébaudeau * 'here' but relocated.
92e05e5de7SAlbert ARIBAUD */
93e05e5de7SAlbert ARIBAUD
94c62c1b3cSVikas Manocha	ldr	r0, [r9, #GD_START_ADDR_SP]	/* sp = gd->start_addr_sp */
95c62c1b3cSVikas Manocha	bic	r0, r0, #7	/* 8-byte alignment for ABI compliance */
96c62c1b3cSVikas Manocha	mov	sp, r0
970d1d4e81SChia-Wei, Wang	ldr r9, [r9, #GD_NEW_GD]
980d1d4e81SChia-Wei, Wang#if 0
99fe1378a9SJeroen Hofstee	ldr	r9, [r9, #GD_BD]		/* r9 = gd->bd */
100fe1378a9SJeroen Hofstee	sub	r9, r9, #GD_SIZE		/* new GD is below bd */
1010d1d4e81SChia-Wei, Wang#endif
102e05e5de7SAlbert ARIBAUD
103e05e5de7SAlbert ARIBAUD	adr	lr, here
10486c21f0aSChia-Wei, Wang#ifdef CONFIG_POSITION_INDEPENDENT
10586c21f0aSChia-Wei, Wang	adr	r0, _main
10686c21f0aSChia-Wei, Wang	ldr	r1, _start_ofs
10786c21f0aSChia-Wei, Wang	add	r0, r1
1080d1d4e81SChia-Wei, Wang#ifdef CONFIG_SPL_BUILD
1090d1d4e81SChia-Wei, Wang	ldr	r1, =CONFIG_SPL_TEXT_BASE
1100d1d4e81SChia-Wei, Wang#else
11186c21f0aSChia-Wei, Wang	ldr	r1, =CONFIG_SYS_TEXT_BASE
1120d1d4e81SChia-Wei, Wang#endif
11386c21f0aSChia-Wei, Wang	sub	r1, r0
11486c21f0aSChia-Wei, Wang	add	lr, r1
115*04a213b5SChia-Wei Wang
116*04a213b5SChia-Wei Wang	ldr	r0, [r9, #GD_ENV_ADDR]		/* r0 = gd->env_addr */
117*04a213b5SChia-Wei Wang	add	r0, r0, r1
118*04a213b5SChia-Wei Wang	str	r0, [r9, #GD_ENV_ADDR]
11986c21f0aSChia-Wei, Wang#endif
120fe1378a9SJeroen Hofstee	ldr	r0, [r9, #GD_RELOC_OFF]		/* r0 = gd->reloc_off */
121e05e5de7SAlbert ARIBAUD	add	lr, lr, r0
12212d8a729Srev13@wp.pl#if defined(CONFIG_CPU_V7M)
12312d8a729Srev13@wp.pl	orr	lr, #1				/* As required by Thumb-only */
12412d8a729Srev13@wp.pl#endif
125fe1378a9SJeroen Hofstee	ldr	r0, [r9, #GD_RELOCADDR]		/* r0 = gd->relocaddr */
126e05e5de7SAlbert ARIBAUD	b	relocate_code
127e05e5de7SAlbert ARIBAUDhere:
128db544b96SAlbert ARIBAUD/*
129db544b96SAlbert ARIBAUD * now relocate vectors
130db544b96SAlbert ARIBAUD */
131db544b96SAlbert ARIBAUD
132db544b96SAlbert ARIBAUD	bl	relocate_vectors
133e05e5de7SAlbert ARIBAUD
134e05e5de7SAlbert ARIBAUD/* Set up final (full) environment */
135e05e5de7SAlbert ARIBAUD
136e05e5de7SAlbert ARIBAUD	bl	c_runtime_cpu_setup	/* we still call old routine here */
137db910353SSimon Glass#endif
138db910353SSimon Glass#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)
139db910353SSimon Glass# ifdef CONFIG_SPL_BUILD
140db910353SSimon Glass	/* Use a DRAM stack for the rest of SPL, if requested */
141db910353SSimon Glass	bl	spl_relocate_stack_gd
142db910353SSimon Glass	cmp	r0, #0
143db910353SSimon Glass	movne	sp, r0
144adc421e4SAlbert ARIBAUD	movne	r9, r0
145db910353SSimon Glass# endif
146e05e5de7SAlbert ARIBAUD	ldr	r0, =__bss_start	/* this is auto-relocated! */
147e05e5de7SAlbert ARIBAUD
148114c86d8SPrzemyslaw Marczak#ifdef CONFIG_USE_ARCH_MEMSET
149114c86d8SPrzemyslaw Marczak	ldr	r3, =__bss_end		/* this is auto-relocated! */
150114c86d8SPrzemyslaw Marczak	mov	r1, #0x00000000		/* prepare zero to clear BSS */
151114c86d8SPrzemyslaw Marczak
152114c86d8SPrzemyslaw Marczak	subs	r2, r3, r0		/* r2 = memset len */
153114c86d8SPrzemyslaw Marczak	bl	memset
154114c86d8SPrzemyslaw Marczak#else
155114c86d8SPrzemyslaw Marczak	ldr	r1, =__bss_end		/* this is auto-relocated! */
156e05e5de7SAlbert ARIBAUD	mov	r2, #0x00000000		/* prepare zero to clear BSS */
157e05e5de7SAlbert ARIBAUD
158e05e5de7SAlbert ARIBAUDclbss_l:cmp	r0, r1			/* while not at end of BSS */
159e05e5de7SAlbert ARIBAUD	strlo	r2, [r0]		/* clear 32-bit BSS word */
160e05e5de7SAlbert ARIBAUD	addlo	r0, r0, #4		/* move to next */
161e05e5de7SAlbert ARIBAUD	blo	clbss_l
162114c86d8SPrzemyslaw Marczak#endif
163e05e5de7SAlbert ARIBAUD
164db910353SSimon Glass#if ! defined(CONFIG_SPL_BUILD)
165e05e5de7SAlbert ARIBAUD	bl coloured_LED_init
166e05e5de7SAlbert ARIBAUD	bl red_led_on
167db910353SSimon Glass#endif
168e05e5de7SAlbert ARIBAUD	/* call board_init_r(gd_t *id, ulong dest_addr) */
169fe1378a9SJeroen Hofstee	mov     r0, r9                  /* gd_t */
170fe1378a9SJeroen Hofstee	ldr	r1, [r9, #GD_RELOCADDR]	/* dest_addr */
171e05e5de7SAlbert ARIBAUD	/* call board_init_r */
1723a649407STom Rini#if CONFIG_IS_ENABLED(SYS_THUMB_BUILD)
17303a3a8aeSDavid Müller (ELSOFT AG)	ldr	lr, =board_init_r	/* this is auto-relocated! */
17403a3a8aeSDavid Müller (ELSOFT AG)	bx	lr
17503a3a8aeSDavid Müller (ELSOFT AG)#else
176e05e5de7SAlbert ARIBAUD	ldr	pc, =board_init_r	/* this is auto-relocated! */
17703a3a8aeSDavid Müller (ELSOFT AG)#endif
178e05e5de7SAlbert ARIBAUD	/* we should not return here. */
179e05e5de7SAlbert ARIBAUD#endif
1809c5feab7SBenoît Thébaudeau
1819c5feab7SBenoît ThébaudeauENDPROC(_main)
18286c21f0aSChia-Wei, Wang
18386c21f0aSChia-Wei, Wang_start_ofs:
18486c21f0aSChia-Wei, Wang	.word _start - _main
185