summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/boards/zynqmp.rst40
-rw-r--r--arch/arm/boards/xilinx-zcu104/Makefile1
-rw-r--r--arch/arm/boards/xilinx-zcu104/board.c18
-rw-r--r--arch/arm/configs/zynqmp_defconfig23
-rw-r--r--arch/arm/dts/zynqmp-zcu104-revA.dts10
-rw-r--r--arch/arm/mach-zynqmp/Makefile2
-rw-r--r--arch/arm/mach-zynqmp/include/mach/zynqmp-bbu.h21
-rw-r--r--arch/arm/mach-zynqmp/zynqmp-bbu.c48
-rw-r--r--arch/arm/mach-zynqmp/zynqmp.c72
-rw-r--r--drivers/clk/zynqmp/clk-gate-zynqmp.c3
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);
}