1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Code shared between SPL and U-Boot proper
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (c) 2015 Google, Inc
5*4882a593Smuzhiyun * Written by Simon Glass <sjg@chromium.org>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <common.h>
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun /* Unfortunately x86 or ARM can't compile this code as gd cannot be assigned */
15*4882a593Smuzhiyun #if !defined(CONFIG_X86) && !defined(CONFIG_ARM)
arch_setup_gd(struct global_data * gd_ptr)16*4882a593Smuzhiyun __weak void arch_setup_gd(struct global_data *gd_ptr)
17*4882a593Smuzhiyun {
18*4882a593Smuzhiyun gd = gd_ptr;
19*4882a593Smuzhiyun }
20*4882a593Smuzhiyun #endif /* !CONFIG_X86 && !CONFIG_ARM */
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun * Allocate reserved space for use as 'globals' from 'top' address and
24*4882a593Smuzhiyun * return 'bottom' address of allocated space
25*4882a593Smuzhiyun *
26*4882a593Smuzhiyun * Notes:
27*4882a593Smuzhiyun *
28*4882a593Smuzhiyun * Actual reservation cannot be done from within this function as
29*4882a593Smuzhiyun * it requires altering the C stack pointer, so this will be done by
30*4882a593Smuzhiyun * the caller upon return from this function.
31*4882a593Smuzhiyun *
32*4882a593Smuzhiyun * IMPORTANT:
33*4882a593Smuzhiyun *
34*4882a593Smuzhiyun * Alignment constraints may differ for each 'chunk' allocated. For now:
35*4882a593Smuzhiyun *
36*4882a593Smuzhiyun * - GD is aligned down on a 16-byte boundary
37*4882a593Smuzhiyun *
38*4882a593Smuzhiyun * - the early malloc arena is not aligned, therefore it follows the stack
39*4882a593Smuzhiyun * alignment constraint of the architecture for which we are bulding.
40*4882a593Smuzhiyun *
41*4882a593Smuzhiyun * - GD is allocated last, so that the return value of this functions is
42*4882a593Smuzhiyun * both the bottom of the reserved area and the address of GD, should
43*4882a593Smuzhiyun * the calling context need it.
44*4882a593Smuzhiyun */
45*4882a593Smuzhiyun
board_init_f_alloc_reserve(ulong top)46*4882a593Smuzhiyun ulong board_init_f_alloc_reserve(ulong top)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun /* Reserve early malloc arena */
49*4882a593Smuzhiyun #if CONFIG_VAL(SYS_MALLOC_F_LEN)
50*4882a593Smuzhiyun top -= CONFIG_VAL(SYS_MALLOC_F_LEN);
51*4882a593Smuzhiyun #endif
52*4882a593Smuzhiyun /* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
53*4882a593Smuzhiyun top = rounddown(top-sizeof(struct global_data), 16);
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun return top;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun /*
59*4882a593Smuzhiyun * Initialize reserved space (which has been safely allocated on the C
60*4882a593Smuzhiyun * stack from the C runtime environment handling code).
61*4882a593Smuzhiyun *
62*4882a593Smuzhiyun * Notes:
63*4882a593Smuzhiyun *
64*4882a593Smuzhiyun * Actual reservation was done by the caller; the locations from base
65*4882a593Smuzhiyun * to base+size-1 (where 'size' is the value returned by the allocation
66*4882a593Smuzhiyun * function above) can be accessed freely without risk of corrupting the
67*4882a593Smuzhiyun * C runtime environment.
68*4882a593Smuzhiyun *
69*4882a593Smuzhiyun * IMPORTANT:
70*4882a593Smuzhiyun *
71*4882a593Smuzhiyun * Upon return from the allocation function above, on some architectures
72*4882a593Smuzhiyun * the caller will set gd to the lowest reserved location. Therefore, in
73*4882a593Smuzhiyun * this initialization function, the global data MUST be placed at base.
74*4882a593Smuzhiyun *
75*4882a593Smuzhiyun * ALSO IMPORTANT:
76*4882a593Smuzhiyun *
77*4882a593Smuzhiyun * On some architectures, gd will already be good when entering this
78*4882a593Smuzhiyun * function. On others, it will only be good once arch_setup_gd() returns.
79*4882a593Smuzhiyun * Therefore, global data accesses must be done:
80*4882a593Smuzhiyun *
81*4882a593Smuzhiyun * - through gd_ptr if before the call to arch_setup_gd();
82*4882a593Smuzhiyun *
83*4882a593Smuzhiyun * - through gd once arch_setup_gd() has been called.
84*4882a593Smuzhiyun *
85*4882a593Smuzhiyun * Do not use 'gd->' until arch_setup_gd() has been called!
86*4882a593Smuzhiyun *
87*4882a593Smuzhiyun * IMPORTANT TOO:
88*4882a593Smuzhiyun *
89*4882a593Smuzhiyun * Initialization for each "chunk" (GD, early malloc arena...) ends with
90*4882a593Smuzhiyun * an incrementation line of the form 'base += <some size>'. The last of
91*4882a593Smuzhiyun * these incrementations seems useless, as base will not be used any
92*4882a593Smuzhiyun * more after this incrementation; but if/when a new "chunk" is appended,
93*4882a593Smuzhiyun * this increment will be essential as it will give base right value for
94*4882a593Smuzhiyun * this new chunk (which will have to end with its own incrementation
95*4882a593Smuzhiyun * statement). Besides, the compiler's optimizer will silently detect
96*4882a593Smuzhiyun * and remove the last base incrementation, therefore leaving that last
97*4882a593Smuzhiyun * (seemingly useless) incrementation causes no code increase.
98*4882a593Smuzhiyun */
99*4882a593Smuzhiyun
board_init_f_init_reserve(ulong base)100*4882a593Smuzhiyun void board_init_f_init_reserve(ulong base)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun struct global_data *gd_ptr;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun /*
105*4882a593Smuzhiyun * clear GD entirely and set it up.
106*4882a593Smuzhiyun * Use gd_ptr, as gd may not be properly set yet.
107*4882a593Smuzhiyun */
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun gd_ptr = (struct global_data *)base;
110*4882a593Smuzhiyun /* zero the area */
111*4882a593Smuzhiyun memset(gd_ptr, '\0', sizeof(*gd));
112*4882a593Smuzhiyun /* set GD unless architecture did it already */
113*4882a593Smuzhiyun #if !defined(CONFIG_ARM)
114*4882a593Smuzhiyun arch_setup_gd(gd_ptr);
115*4882a593Smuzhiyun #endif
116*4882a593Smuzhiyun /* next alloc will be higher by one GD plus 16-byte alignment */
117*4882a593Smuzhiyun base += roundup(sizeof(struct global_data), 16);
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun /*
120*4882a593Smuzhiyun * record early malloc arena start.
121*4882a593Smuzhiyun * Use gd as it is now properly set for all architectures.
122*4882a593Smuzhiyun */
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun #if CONFIG_VAL(SYS_MALLOC_F_LEN)
125*4882a593Smuzhiyun /* go down one 'early malloc arena' */
126*4882a593Smuzhiyun gd->malloc_base = base;
127*4882a593Smuzhiyun /* next alloc will be higher by one 'early malloc arena' size */
128*4882a593Smuzhiyun base += CONFIG_VAL(SYS_MALLOC_F_LEN);
129*4882a593Smuzhiyun #endif
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun /*
133*4882a593Smuzhiyun * Board-specific Platform code can init boot flags if needed
134*4882a593Smuzhiyun */
board_init_f_boot_flags(void)135*4882a593Smuzhiyun __weak int board_init_f_boot_flags(void)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun gd->baudrate = CONFIG_BAUDRATE;
138*4882a593Smuzhiyun gd->serial.baudrate = CONFIG_BAUDRATE;
139*4882a593Smuzhiyun gd->serial.addr = CONFIG_DEBUG_UART_BASE;
140*4882a593Smuzhiyun gd->serial.using_pre_serial = 0;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun return 0;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun /*
146*4882a593Smuzhiyun * Board-specific Platform code can reimplement show_boot_progress () if needed
147*4882a593Smuzhiyun */
show_boot_progress(int val)148*4882a593Smuzhiyun __weak void show_boot_progress(int val) {}
149