[RFC PATCH] arm64: zynqmp: Add support for placing TFA from beginning of OCM

Michal Simek michal.simek at xilinx.com
Wed May 5 14:50:00 CEST 2021


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 at 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

diff --git a/arch/arm/mach-zynqmp/Kconfig b/arch/arm/mach-zynqmp/Kconfig
index f1301f6661a1..8578c6910701 100644
--- a/arch/arm/mach-zynqmp/Kconfig
+++ b/arch/arm/mach-zynqmp/Kconfig
@@ -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
 
diff --git a/arch/arm/mach-zynqmp/clk.c b/arch/arm/mach-zynqmp/clk.c
index 1e6e726e8792..ad2636169a1a 100644
--- a/arch/arm/mach-zynqmp/clk.c
+++ b/arch/arm/mach-zynqmp/clk.c
@@ -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();
 
diff --git a/arch/arm/mach-zynqmp/cpu.c b/arch/arm/mach-zynqmp/cpu.c
index 29743cae5aab..fa2d6e730cba 100644
--- a/arch/arm/mach-zynqmp/cpu.c
+++ b/arch/arm/mach-zynqmp/cpu.c
@@ -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();
diff --git a/arch/arm/mach-zynqmp/handoff.c b/arch/arm/mach-zynqmp/handoff.c
index 7d7ab9da6ec2..4c5a81fc4cad 100644
--- a/arch/arm/mach-zynqmp/handoff.c
+++ b/arch/arm/mach-zynqmp/handoff.c
@@ -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;
 }
diff --git a/arch/arm/mach-zynqmp/include/mach/psu_init_gpl.h b/arch/arm/mach-zynqmp/include/mach/psu_init_gpl.h
index e37acda2f89e..9cccd2139700 100644
--- a/arch/arm/mach-zynqmp/include/mach/psu_init_gpl.h
+++ b/arch/arm/mach-zynqmp/include/mach/psu_init_gpl.h
@@ -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_ */
diff --git a/arch/arm/mach-zynqmp/include/mach/sys_proto.h b/arch/arm/mach-zynqmp/include/mach/sys_proto.h
index 1c12eac715e5..c1ab685c3ce4 100644
--- a/arch/arm/mach-zynqmp/include/mach/sys_proto.h
+++ b/arch/arm/mach-zynqmp/include/mach/sys_proto.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
diff --git a/arch/arm/mach-zynqmp/spl.c b/arch/arm/mach-zynqmp/spl.c
index 88386b23e5da..f57835143041 100644
--- a/arch/arm/mach-zynqmp/spl.c
+++ b/arch/arm/mach-zynqmp/spl.c
@@ -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;
 }
diff --git a/arch/arm/mach-zynqmp/u-boot-spl.lds b/arch/arm/mach-zynqmp/u-boot-spl.lds
new file mode 100644
index 000000000000..5b71d5a35142
--- /dev/null
+++ b/arch/arm/mach-zynqmp/u-boot-spl.lds
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2013
+ * David Feng <fenghua at phytium.com.cn>
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <garyj at denx.de>
+ *
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ *	Aneesh V <aneesh at 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*) }
+}
diff --git a/board/xilinx/zynqmp/pm_cfg_obj.h b/board/xilinx/zynqmp/pm_cfg_obj.h
index 86e785490ced..232dcd0ce116 100644
--- a/board/xilinx/zynqmp/pm_cfg_obj.h
+++ b/board/xilinx/zynqmp/pm_cfg_obj.h
@@ -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;
diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c
index d05f0b2e1202..e56cfa2cc520 100644
--- a/board/xilinx/zynqmp/zynqmp.c
+++ b/board/xilinx/zynqmp/zynqmp.c
@@ -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;
diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c
index d4dc856bafa4..08bcdf5bb024 100644
--- a/drivers/firmware/firmware-zynqmp.c
+++ b/drivers/firmware/firmware-zynqmp.c
@@ -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];
-- 
2.31.1



More information about the U-Boot mailing list