@@ -1,5 +1,8 @@
if ARCH_ZYNQMP
+config SPL_LDSCRIPT
+ default "arch/arm/mach-zynqmp/u-boot-spl.lds"
+
config SPL_FS_FAT
default y
@@ -14,7 +14,7 @@
DECLARE_GLOBAL_DATA_PTR;
-unsigned long zynqmp_get_system_timer_freq(void)
+unsigned long __splinit zynqmp_get_system_timer_freq(void)
{
u32 ver = zynqmp_get_silicon_version();
@@ -35,7 +35,7 @@ unsigned long zynqmp_get_system_timer_freq(void)
* clock framework. The framework must not be used before this function had been
* called.
*/
-int set_cpu_clk_info(void)
+int __splinit set_cpu_clk_info(void)
{
gd->cpu_clk = get_tbclk();
@@ -105,7 +105,7 @@ void mem_map_fill(void)
struct mm_region *mem_map = zynqmp_mem_map;
-u64 get_page_table_size(void)
+u64 __splinit get_page_table_size(void)
{
return 0x14000;
}
@@ -130,7 +130,7 @@ int arm_reserve_mmu(void)
}
#endif
-static unsigned int zynqmp_get_silicon_version_secure(void)
+static unsigned int __splinit zynqmp_get_silicon_version_secure(void)
{
u32 ver;
@@ -141,7 +141,7 @@ static unsigned int zynqmp_get_silicon_version_secure(void)
return ver;
}
-unsigned int zynqmp_get_silicon_version(void)
+unsigned int __splinit zynqmp_get_silicon_version(void)
{
if (current_el() == 3)
return zynqmp_get_silicon_version_secure();
@@ -72,7 +72,7 @@ struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl32_entry,
{
struct xfsbl_atf_handoff_params *atfhandoffparams;
- atfhandoffparams = (void *)CONFIG_SPL_TEXT_BASE;
+ atfhandoffparams = (void *)0xfffe0000;
atfhandoffparams->magic[0] = 'X';
atfhandoffparams->magic[1] = 'L';
atfhandoffparams->magic[2] = 'N';
@@ -86,7 +86,7 @@ struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl32_entry,
atfhandoffparams->num_entries++;
}
- writel(CONFIG_SPL_TEXT_BASE, &pmu_base->gen_storage6);
+ writel(0xfffe0000, &pmu_base->gen_storage6);
return NULL;
}
@@ -5,22 +5,23 @@
#include <asm/io.h>
#include <common.h>
+#include <asm/arch/sys_proto.h>
-int mask_pollonvalue(unsigned long add, u32 mask, u32 value);
+int __splinit mask_pollonvalue(unsigned long add, u32 mask, u32 value);
-int mask_poll(u32 add, u32 mask);
+int __splinit mask_poll(u32 add, u32 mask);
-u32 mask_read(u32 add, u32 mask);
+u32 __splinit mask_read(u32 add, u32 mask);
-void mask_delay(u32 delay);
+void __splinit mask_delay(u32 delay);
-void psu_mask_write(unsigned long offset, unsigned long mask,
- unsigned long val);
+void __splinit psu_mask_write(unsigned long offset, unsigned long mask,
+ unsigned long val);
-void prog_reg(unsigned long addr, unsigned long mask,
- unsigned long shift, unsigned long value);
+void __splinit prog_reg(unsigned long addr, unsigned long mask,
+ unsigned long shift, unsigned long value);
-int psu_init(void);
-unsigned long psu_post_config_data(void);
+int __splinit psu_init(void);
+unsigned long __splinit psu_post_config_data(void);
#endif /* _PSU_INIT_GPL_H_ */
@@ -7,6 +7,12 @@
#ifndef _ASM_ARCH_SYS_PROTO_H
#define _ASM_ARCH_SYS_PROTO_H
+#if CONFIG_SPL_BUILD
+#define __splinit __section(.splinit)
+#else
+#define __splinit
+#endif
+
#define ZYNQMP_CSU_SILICON_VER_MASK 0xF
#define KEY_PTR_LEN 32
#define IV_SIZE 12
@@ -18,13 +18,13 @@
#include <asm/arch/psu_init_gpl.h>
#include <asm/arch/sys_proto.h>
-void board_init_f(ulong dummy)
+void __splinit board_init_f(ulong dummy)
{
board_early_init_f();
board_early_init_r();
}
-static void ps_mode_reset(ulong mode)
+static void __splinit ps_mode_reset(ulong mode)
{
writel(mode << ZYNQMP_CRL_APB_BOOT_PIN_CTRL_OUT_EN_SHIFT,
&crlapb_base->boot_pin_ctrl);
@@ -43,7 +43,7 @@ static void ps_mode_reset(ulong mode)
#endif
#ifdef CONFIG_SPL_BOARD_INIT
-void spl_board_init(void)
+void __splinit spl_board_init(void)
{
preloader_console_init();
ps_mode_reset(MODE_RESET);
@@ -52,7 +52,7 @@ void spl_board_init(void)
}
#endif
-void board_boot_order(u32 *spl_boot_list)
+void __splinit board_boot_order(u32 *spl_boot_list)
{
spl_boot_list[0] = spl_boot_device();
@@ -64,7 +64,7 @@ void board_boot_order(u32 *spl_boot_list)
spl_boot_list[2] = BOOT_DEVICE_RAM;
}
-u32 spl_boot_device(void)
+u32 __splinit spl_boot_device(void)
{
u32 reg = 0;
u8 bootmode;
@@ -114,7 +114,7 @@ u32 spl_boot_device(void)
}
#ifdef CONFIG_SPL_OS_BOOT
-int spl_start_uboot(void)
+int __splinit spl_start_uboot(void)
{
return 0;
}
new file mode 100644
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2013
+ * David Feng <fenghua@phytium.com.cn>
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+ *
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ * Aneesh V <aneesh@ti.com>
+ */
+
+MEMORY { .sram : ORIGIN = IMAGE_TEXT_BASE,
+ LENGTH = IMAGE_MAX_SIZE }
+MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR,
+ LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
+
+OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
+OUTPUT_ARCH(aarch64)
+ENTRY(_start)
+SECTIONS
+{
+ .text : {
+ . = ALIGN(8);
+ *(.__image_copy_start)
+ CPUDIR/start.o (.text*)
+ *(.splinit*)
+ . = ALIGN(0x18000);
+ *(.text*)
+ } >.sram
+
+ .rodata : {
+ . = ALIGN(8);
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ } >.sram
+
+ .data : {
+ . = ALIGN(8);
+ *(.data*)
+ } >.sram
+
+#ifdef CONFIG_SPL_RECOVER_DATA_SECTION
+ .data_save : {
+ *(.__data_save_start)
+ . = SIZEOF(.data);
+ *(.__data_save_end)
+ } >.sram
+#endif
+
+ .u_boot_list : {
+ . = ALIGN(8);
+ KEEP(*(SORT(.u_boot_list*)));
+ } >.sram
+
+ .image_copy_end : {
+ . = ALIGN(8);
+ *(.__image_copy_end)
+ } >.sram
+
+ .end : {
+ . = ALIGN(8);
+ *(.__end)
+ } >.sram
+
+ _image_binary_end = .;
+
+ .bss_start (NOLOAD) : {
+ . = ALIGN(8);
+ KEEP(*(.__bss_start));
+ } >.sdram
+
+ .bss (NOLOAD) : {
+ *(.bss*)
+ . = ALIGN(8);
+ } >.sdram
+
+ .bss_end (NOLOAD) : {
+ KEEP(*(.__bss_end));
+ } >.sdram
+
+ /DISCARD/ : { *(.dynsym) }
+ /DISCARD/ : { *(.dynstr*) }
+ /DISCARD/ : { *(.dynamic*) }
+ /DISCARD/ : { *(.plt*) }
+ /DISCARD/ : { *(.interp*) }
+ /DISCARD/ : { *(.gnu*) }
+}
@@ -5,5 +5,5 @@
* Declaration of PMU config object binary blob linked in at build time.
*/
-extern const u32 zynqmp_pm_cfg_obj[];
-extern const int zynqmp_pm_cfg_obj_size;
+extern const u32 __splinit zynqmp_pm_cfg_obj[];
+extern const int __splinit zynqmp_pm_cfg_obj_size;
@@ -185,7 +185,7 @@ static const struct {
},
};
-static char *zynqmp_get_silicon_idcode_name(void)
+static char __splinit *zynqmp_get_silicon_idcode_name(void)
{
u32 i;
u32 idcode, idcode2;
@@ -278,7 +278,7 @@ static char *zynqmp_get_silicon_idcode_name(void)
}
#endif
-int board_early_init_f(void)
+int __splinit board_early_init_f(void)
{
#if defined(CONFIG_ZYNQMP_PSU_INIT_ENABLED)
int ret;
@@ -300,7 +300,7 @@ int board_early_init_f(void)
return 0;
}
-static int multi_boot(void)
+static int __splinit multi_boot(void)
{
u32 multiboot;
@@ -314,7 +314,7 @@ static int multi_boot(void)
#define PS_SYSMON_ANALOG_BUS_VAL 0x3210
#define PS_SYSMON_ANALOG_BUS_REG 0xFFA50914
-int board_init(void)
+int __splinit board_init(void)
{
#if defined(CONFIG_ZYNQMP_FIRMWARE)
struct udevice *dev;
@@ -353,7 +353,7 @@ int board_init(void)
return 0;
}
-int board_early_init_r(void)
+int __splinit board_early_init_r(void)
{
u32 val;
@@ -396,7 +396,7 @@ unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc,
}
#if !defined(CONFIG_SYS_SDRAM_BASE) && !defined(CONFIG_SYS_SDRAM_SIZE)
-int dram_init_banksize(void)
+int __splinit dram_init_banksize(void)
{
int ret;
@@ -409,7 +409,7 @@ int dram_init_banksize(void)
return 0;
}
-int dram_init(void)
+int __splinit dram_init(void)
{
if (fdtdec_setup_mem_size_base() != 0)
return -EINVAL;
@@ -417,7 +417,7 @@ int dram_init(void)
return 0;
}
#else
-int dram_init_banksize(void)
+int __splinit dram_init_banksize(void)
{
gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
gd->bd->bi_dram[0].size = get_effective_memsize();
@@ -427,7 +427,7 @@ int dram_init_banksize(void)
return 0;
}
-int dram_init(void)
+int __splinit dram_init(void)
{
gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE,
CONFIG_SYS_SDRAM_SIZE);
@@ -440,7 +440,7 @@ void reset_cpu(void)
{
}
-static u8 __maybe_unused zynqmp_get_bootmode(void)
+static u8 __maybe_unused __splinit zynqmp_get_bootmode(void)
{
u8 bootmode;
u32 reg = 0;
@@ -473,7 +473,7 @@ static const struct {
{}
};
-static int reset_reason(void)
+static int __splinit reset_reason(void)
{
u32 reg;
int i, ret;
@@ -55,7 +55,7 @@ static int ipi_req(const u32 *req, size_t req_len, u32 *res, size_t res_maxlen)
return ret;
}
-unsigned int zynqmp_firmware_version(void)
+unsigned int __splinit zynqmp_firmware_version(void)
{
int ret;
u32 ret_payload[PAYLOAD_ARG_CNT];
@@ -88,7 +88,7 @@ unsigned int zynqmp_firmware_version(void)
* @cfg_obj: Pointer to the configuration object
* @size: Size of @cfg_obj in bytes
*/
-void zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size)
+void __splinit zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size)
{
int err;
u32 ret_payload[PAYLOAD_ARG_CNT];
Xilinx TFA is normally placed to OCM at 0xfffea000 with a max size of 88kB. By adding new and new features to TFA this split is reaching its limit that there would be a need to change structures a little bit. The idea is to resort SPL (potentially also Xilinx first stage bootloader FSBL) that the beginning of the binary contains only the initcode which is called only once before loading other images. The way how this can be done is to use custom linker script and mark early functions with __splinit to place them at the beginning of OCM. Also make sure that space is bigger than current 88kB. The patch is doing a barrier at 96kB just to prove that it is possible to do so. Code which is marked with __splinit is only coming from Xilinx Zynqmp code but I would expect there is also generic code which can be marked like that. Signed-off-by: Michal Simek <michal.simek@xilinx.com> --- Hi, I am sending this series to start discussion how this can be done in a better/generic way. Right now I have marked only the part of zynqmp code which is just 0x3d54 = ~15kB of code. And then there is 81kB empty space followed by generic code. Linux is marking this code with __init and this is pretty much a similar idea to have it in the same location and being able to reuse that location for different purposes I expect all functions in include/init.h are exactly like that and there will be likely others too. Thanks, Michal --- arch/arm/mach-zynqmp/Kconfig | 3 + arch/arm/mach-zynqmp/clk.c | 4 +- arch/arm/mach-zynqmp/cpu.c | 6 +- arch/arm/mach-zynqmp/handoff.c | 4 +- .../mach-zynqmp/include/mach/psu_init_gpl.h | 21 ++--- arch/arm/mach-zynqmp/include/mach/sys_proto.h | 6 ++ arch/arm/mach-zynqmp/spl.c | 12 +-- arch/arm/mach-zynqmp/u-boot-spl.lds | 88 +++++++++++++++++++ board/xilinx/zynqmp/pm_cfg_obj.h | 4 +- board/xilinx/zynqmp/zynqmp.c | 22 ++--- drivers/firmware/firmware-zynqmp.c | 4 +- 11 files changed, 136 insertions(+), 38 deletions(-) create mode 100644 arch/arm/mach-zynqmp/u-boot-spl.lds