diff options
-rw-r--r-- | Documentation/boards/zynqmp.rst | 40 | ||||
-rw-r--r-- | arch/arm/boards/xilinx-zcu104/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/boards/xilinx-zcu104/board.c | 18 | ||||
-rw-r--r-- | arch/arm/configs/zynqmp_defconfig | 23 | ||||
-rw-r--r-- | arch/arm/dts/zynqmp-zcu104-revA.dts | 10 | ||||
-rw-r--r-- | arch/arm/mach-zynqmp/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-zynqmp/include/mach/zynqmp-bbu.h | 21 | ||||
-rw-r--r-- | arch/arm/mach-zynqmp/zynqmp-bbu.c | 48 | ||||
-rw-r--r-- | arch/arm/mach-zynqmp/zynqmp.c | 72 | ||||
-rw-r--r-- | drivers/clk/zynqmp/clk-gate-zynqmp.c | 3 |
10 files changed, 238 insertions, 0 deletions
diff --git a/Documentation/boards/zynqmp.rst b/Documentation/boards/zynqmp.rst new file mode 100644 index 0000000000..05d41c401d --- /dev/null +++ b/Documentation/boards/zynqmp.rst @@ -0,0 +1,40 @@ +Xilinx ZynqMP Ultrascale+ +========================= + +Barebox has support as a second stage boot loader for the Xilinx ZynqMP +Ultrascale+. + +Image creation +-------------- + +Currently, Barebox only supports booting as a second stage boot loader from an +SD-card. It relies on the FSBL_ to initialize the base system including sdram +setup and pin muxing. + +The ZynqMP defconfig supports the ZCU104 reference board. Use it to build the +Barebox image:: + + make ARCH=arm64 zynqmp_defconfig + make ARCH=arm64 + +.. note:: The resulting image ``images/barebox-zynqmp-zcu104.img`` is **not** an image + that can directly be booted on the ZynqMP. + +For a bootable BOOT.BIN image, you also need to build the FSBL_ and a ZynqMP +TF-A. Prepare these separately using the respective instructions. + +Use bootgen_ or ``mkimage -T zynqmpbif`` from the U-boot tools to build the +final BOOT.BIN image that can be loaded by the ROM code. Check the +instructions for these tools how to prepare the BOOT.BIN image. + +Create a FAT partition as the first partition of the SD card and copy the +produced BOOT.BIN into this partition. + +.. _FSBL: `https://github.com/Xilinx/embeddedsw/` +.. _bootgen: `https://github.com/Xilinx/bootgen` + +Booting Barebox +--------------- + +The FSBL loads the TF-A and Barebox, jumps to the TF-A, which will then return +to Barebox. Afterwards, you can use Barebox as usual. diff --git a/arch/arm/boards/xilinx-zcu104/Makefile b/arch/arm/boards/xilinx-zcu104/Makefile index 884d6e63b0..297f77d57a 100644 --- a/arch/arm/boards/xilinx-zcu104/Makefile +++ b/arch/arm/boards/xilinx-zcu104/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-or-later +obj-y += board.o lwl-y += lowlevel.o lowlevel_init.o diff --git a/arch/arm/boards/xilinx-zcu104/board.c b/arch/arm/boards/xilinx-zcu104/board.c new file mode 100644 index 0000000000..7654d2bfac --- /dev/null +++ b/arch/arm/boards/xilinx-zcu104/board.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020 Michael Tretter <m.tretter@pengutronix.de> + */ + +#include <common.h> +#include <init.h> +#include <mach/zynqmp-bbu.h> + +static int zcu104_register_update_handler(void) +{ + if (!of_machine_is_compatible("xlnx,zynqmp-zcu104")) + return 0; + + return zynqmp_bbu_register_handler("SD", "/boot/BOOT.BIN", + BBU_HANDLER_FLAG_DEFAULT); +} +device_initcall(zcu104_register_update_handler); diff --git a/arch/arm/configs/zynqmp_defconfig b/arch/arm/configs/zynqmp_defconfig index 6f5612fa92..2cd8781332 100644 --- a/arch/arm/configs/zynqmp_defconfig +++ b/arch/arm/configs/zynqmp_defconfig @@ -1,5 +1,6 @@ CONFIG_ARCH_ZYNQMP=y CONFIG_MACH_XILINX_ZCU104=y +CONFIG_ARM_PSCI_CLIENT=y CONFIG_MMU=y CONFIG_MALLOC_SIZE=0x0 CONFIG_MALLOC_TLSF=y @@ -12,32 +13,54 @@ CONFIG_BOOTM_SHOW_TYPE=y CONFIG_BOOTM_VERBOSE=y CONFIG_BOOTM_INITRD=y CONFIG_BOOTM_OFTREE=y +CONFIG_BLSPEC=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y +CONFIG_RESET_SOURCE=y CONFIG_LONGHELP=y CONFIG_CMD_MEMINFO=y CONFIG_CMD_GO=y CONFIG_CMD_RESET=y CONFIG_CMD_PARTITION=y CONFIG_CMD_EXPORT=y +CONFIG_CMD_DEFAULTENV=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_MAGICVAR=y CONFIG_CMD_MAGICVAR_HELP=y CONFIG_CMD_SAVEENV=y CONFIG_CMD_LN=y CONFIG_CMD_SLEEP=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_MIITOOL=y +CONFIG_CMD_PING=y +CONFIG_CMD_TFTP=y CONFIG_CMD_EDIT=y CONFIG_CMD_MENU=y CONFIG_CMD_MENU_MANAGEMENT=y CONFIG_CMD_READLINE=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_CLK=y +CONFIG_CMD_DETECT=y +CONFIG_CMD_BAREBOX_UPDATE=y +CONFIG_CMD_FIRMWARELOAD=y +CONFIG_CMD_OF_OVERLAY=y CONFIG_CMD_OFTREE=y CONFIG_CMD_TIME=y CONFIG_NET=y +CONFIG_NET_NFS=y +CONFIG_OF_BAREBOX_DRIVERS=y +CONFIG_OF_BAREBOX_ENV_IN_FS=y +CONFIG_OF_OVERLAY_LIVE=y CONFIG_DRIVER_SERIAL_CADENCE=y CONFIG_DRIVER_NET_MACB=y +CONFIG_DP83867_PHY=y # CONFIG_SPI is not set CONFIG_MCI=y CONFIG_MCI_ARASAN=y CONFIG_FIRMWARE_ZYNQMP_FPGA=y +# CONFIG_VIRTIO_MENU is not set +CONFIG_FS_EXT4=y +CONFIG_FS_TFTP=y +CONFIG_FS_NFS=y +CONFIG_FS_FAT=y +CONFIG_FS_FAT_WRITE=y CONFIG_DIGEST=y diff --git a/arch/arm/dts/zynqmp-zcu104-revA.dts b/arch/arm/dts/zynqmp-zcu104-revA.dts index 8c467ee970..95b60a6b1d 100644 --- a/arch/arm/dts/zynqmp-zcu104-revA.dts +++ b/arch/arm/dts/zynqmp-zcu104-revA.dts @@ -8,3 +8,13 @@ */ #include <arm64/xilinx/zynqmp-zcu104-revA.dts> + +/ { + chosen { + environment { + compatible = "barebox,environment"; + device-path = &sdhci1, "partname:0"; + file-path = "barebox.env"; + }; + }; +}; diff --git a/arch/arm/mach-zynqmp/Makefile b/arch/arm/mach-zynqmp/Makefile index 021efc94af..e24a43c0d5 100644 --- a/arch/arm/mach-zynqmp/Makefile +++ b/arch/arm/mach-zynqmp/Makefile @@ -1,2 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-or-later obj-y += firmware-zynqmp.o +obj-y += zynqmp.o +obj-$(CONFIG_BAREBOX_UPDATE) += zynqmp-bbu.o diff --git a/arch/arm/mach-zynqmp/include/mach/zynqmp-bbu.h b/arch/arm/mach-zynqmp/include/mach/zynqmp-bbu.h new file mode 100644 index 0000000000..8502791ee0 --- /dev/null +++ b/arch/arm/mach-zynqmp/include/mach/zynqmp-bbu.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 Michael Tretter <m.tretter@pengutronix.de> + */ +#ifndef __MACH_ZYNQMP_BBU_H +#define __MACH_ZYNQMP_BBU_H + +#include <bbu.h> + +#ifdef CONFIG_BAREBOX_UPDATE +int zynqmp_bbu_register_handler(const char *name, char *devicefile, + unsigned long flags); +#else +static int zynqmp_bbu_register_handler(const char *name, char *devicefile, + unsigned long flags) +{ + return 0; +}; +#endif + +#endif /* __MACH_ZYNQMP_BBU_H */ diff --git a/arch/arm/mach-zynqmp/zynqmp-bbu.c b/arch/arm/mach-zynqmp/zynqmp-bbu.c new file mode 100644 index 0000000000..d1197c01dc --- /dev/null +++ b/arch/arm/mach-zynqmp/zynqmp-bbu.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020 Michael Tretter <m.tretter@pengutronix.de> + */ + +#include <common.h> +#include <libfile.h> +#include <mach/zynqmp-bbu.h> + +static int zynqmp_bbu_handler(struct bbu_handler *handler, + struct bbu_data *data) +{ + int ret = 0; + + ret = bbu_confirm(data); + if (ret) + return ret; + + ret = copy_file(data->imagefile, data->devicefile, 1); + if (ret < 0) { + pr_err("update failed: %s", strerror(-ret)); + return ret; + } + + return ret; +} + +int zynqmp_bbu_register_handler(const char *name, char *devicefile, + unsigned long flags) +{ + struct bbu_handler *handler; + int ret = 0; + + if (!name || !devicefile) + return -EINVAL; + + handler = xzalloc(sizeof(*handler)); + handler->name = name; + handler->devicefile = devicefile; + handler->flags = flags; + handler->handler = zynqmp_bbu_handler; + + ret = bbu_register_handler(handler); + if (ret) + free(handler); + + return ret; +} diff --git a/arch/arm/mach-zynqmp/zynqmp.c b/arch/arm/mach-zynqmp/zynqmp.c new file mode 100644 index 0000000000..5871c145be --- /dev/null +++ b/arch/arm/mach-zynqmp/zynqmp.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020 Michael Tretter <m.tretter@pengutronix.de> + */ + +#include <common.h> +#include <init.h> +#include <linux/types.h> +#include <reset_source.h> + +#define ZYNQMP_CRL_APB_BASE 0xff5e0000 +#define ZYNQMP_CRL_APB_RESET_REASON (ZYNQMP_CRL_APB_BASE + 0x220) + +/* External POR: The PS_POR_B reset signal pin was asserted. */ +#define ZYNQMP_CRL_APB_RESET_REASON_EXTERNAL BIT(0) +/* Internal POR: A system error triggered a POR reset. */ +#define ZYNQMP_CRL_APB_RESET_REASON_INTERNAL BIT(1) +/* Internal system reset; A system error triggered a system reset. */ +#define ZYNQMP_CRL_APB_RESET_REASON_PMU BIT(2) +/* PS-only reset: Write to PMU_GLOBAL.GLOBAL_RESET [PS_ONLY_RST]. */ +#define ZYNQMP_CRL_APB_RESET_REASON_PSONLY BIT(3) +/* External system reset: The PS_SRST_B reset signal pin was asserted. */ +#define ZYNQMP_CRL_APB_RESET_REASON_SRST BIT(4) +/* Software system reset: Write to RESET_CTRL [soft_reset]. */ +#define ZYNQMP_CRL_APB_RESET_REASON_SOFT BIT(5) +/* Software debugger reset: Write to BLOCKONLY_RST [debug_only]. */ +#define ZYNQMP_CRL_APB_RESET_REASON_DEBUG_SYS BIT(6) + +struct zynqmp_reset_reason { + u32 mask; + enum reset_src_type type; +}; + +static const struct zynqmp_reset_reason reset_reasons[] = { + { ZYNQMP_CRL_APB_RESET_REASON_DEBUG_SYS, RESET_JTAG }, + { ZYNQMP_CRL_APB_RESET_REASON_SOFT, RESET_RST }, + { ZYNQMP_CRL_APB_RESET_REASON_SRST, RESET_POR }, + { ZYNQMP_CRL_APB_RESET_REASON_PSONLY, RESET_POR }, + { ZYNQMP_CRL_APB_RESET_REASON_PMU, RESET_POR }, + { ZYNQMP_CRL_APB_RESET_REASON_INTERNAL, RESET_POR }, + { ZYNQMP_CRL_APB_RESET_REASON_EXTERNAL, RESET_POR }, + { /* sentinel */ } +}; + +static enum reset_src_type zynqmp_get_reset_src(void) +{ + enum reset_src_type type = RESET_UKWN; + unsigned int i; + u32 val; + + val = readl(ZYNQMP_CRL_APB_RESET_REASON); + + for (i = 0; i < ARRAY_SIZE(reset_reasons); i++) { + if (val & reset_reasons[i].mask) { + type = reset_reasons[i].type; + break; + } + } + + pr_info("ZynqMP reset reason %s (ZYNQMP_CRL_APB_RESET_REASON: 0x%08x)\n", + reset_source_to_string(type), val); + + return type; +} + +static int zynqmp_init(void) +{ + reset_source_set(zynqmp_get_reset_src()); + + return 0; +} +postcore_initcall(zynqmp_init); diff --git a/drivers/clk/zynqmp/clk-gate-zynqmp.c b/drivers/clk/zynqmp/clk-gate-zynqmp.c index a3b9ee21e5..493c1dfeaa 100644 --- a/drivers/clk/zynqmp/clk-gate-zynqmp.c +++ b/drivers/clk/zynqmp/clk-gate-zynqmp.c @@ -28,6 +28,9 @@ static int zynqmp_clk_gate_enable(struct clk_hw *hw) { struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw); + if (clk_hw_is_enabled(hw)) + return 0; + return gate->ops->clock_enable(gate->clk_id); } |