summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-zynqmp/zynqmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-zynqmp/zynqmp.c')
-rw-r--r--arch/arm/mach-zynqmp/zynqmp.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/arch/arm/mach-zynqmp/zynqmp.c b/arch/arm/mach-zynqmp/zynqmp.c
new file mode 100644
index 0000000000..f86bda1693
--- /dev/null
+++ b/arch/arm/mach-zynqmp/zynqmp.c
@@ -0,0 +1,160 @@
+// 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 <bootsource.h>
+#include <reset_source.h>
+
+#define ZYNQMP_CRL_APB_BASE 0xff5e0000
+#define ZYNQMP_CRL_APB_BOOT_MODE_USER (ZYNQMP_CRL_APB_BASE + 0x200)
+#define ZYNQMP_CRL_APB_RESET_REASON (ZYNQMP_CRL_APB_BASE + 0x220)
+
+/* PSJTAG interface, PS dedicated pins. */
+#define ZYNQMP_CRL_APB_BOOT_MODE_PSJTAG 0x0
+/* SPI 24-bit addressing */
+#define ZYNQMP_CRL_APB_BOOT_MODE_QSPI24 0x1
+/* SPI 32-bit addressing */
+#define ZYNQMP_CRL_APB_BOOT_MODE_QSPI32 0x2
+/* SD 2.0 card @ controller 0 */
+#define ZYNQMP_CRL_APB_BOOT_MODE_SD0 0x3
+/* SPI NAND flash */
+#define ZYNQMP_CRL_APB_BOOT_MODE_NAND 0x4
+/* SD 2.0 card @ controller 1 */
+#define ZYNQMP_CRL_APB_BOOT_MODE_SD1 0x5
+/* eMMC @ controller 1 */
+#define ZYNQMP_CRL_APB_BOOT_MODE_EMMC 0x6
+/* USB 2.0 */
+#define ZYNQMP_CRL_APB_BOOT_MODE_USB 0x7
+/* PJTAG connection 0 option. */
+#define ZYNQMP_CRL_APB_BOOT_MODE_PJTAG0 0x8
+/* PJTAG connection 1 option. */
+#define ZYNQMP_CRL_APB_BOOT_MODE_PJTAG1 0x9
+/* SD 3.0 card (level-shifted) @ controller 1 */
+#define ZYNQMP_CRL_APB_BOOT_MODE_SD1LS 0xE
+
+/* 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)
+
+static void zynqmp_get_bootsource(enum bootsource *src, int *instance)
+{
+ u32 v;
+
+ if (!src || !instance)
+ return;
+
+ v = readl(ZYNQMP_CRL_APB_BOOT_MODE_USER);
+ v &= 0x0F;
+
+ /* cf. Table 11-1 "Boot Modes" in UG1085 Zynq UltraScale+ Device TRM */
+ switch (v) {
+ case ZYNQMP_CRL_APB_BOOT_MODE_PSJTAG:
+ case ZYNQMP_CRL_APB_BOOT_MODE_PJTAG0:
+ case ZYNQMP_CRL_APB_BOOT_MODE_PJTAG1:
+ *src = BOOTSOURCE_JTAG;
+ *instance = 0;
+ break;
+
+ case ZYNQMP_CRL_APB_BOOT_MODE_QSPI24:
+ case ZYNQMP_CRL_APB_BOOT_MODE_QSPI32:
+ *src = BOOTSOURCE_SPI;
+ *instance = 0;
+ break;
+
+ case ZYNQMP_CRL_APB_BOOT_MODE_SD0:
+ *src = BOOTSOURCE_MMC;
+ *instance = 0;
+ break;
+
+ case ZYNQMP_CRL_APB_BOOT_MODE_NAND:
+ *src = BOOTSOURCE_SPI_NAND;
+ *instance = 0;
+ break;
+
+ case ZYNQMP_CRL_APB_BOOT_MODE_SD1:
+ case ZYNQMP_CRL_APB_BOOT_MODE_EMMC:
+ case ZYNQMP_CRL_APB_BOOT_MODE_SD1LS:
+ *src = BOOTSOURCE_MMC;
+ *instance = 1;
+ break;
+
+ case ZYNQMP_CRL_APB_BOOT_MODE_USB:
+ *src = BOOTSOURCE_USB;
+ *instance = 0;
+ break;
+
+ default:
+ *src = BOOTSOURCE_UNKNOWN;
+ *instance = BOOTSOURCE_INSTANCE_UNKNOWN;
+ break;
+ }
+}
+
+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)
+{
+ enum bootsource boot_src;
+ int boot_instance;
+
+ if (!of_machine_is_compatible("xlnx,zynqmp"))
+ return 0;
+
+ zynqmp_get_bootsource(&boot_src, &boot_instance);
+ bootsource_set_raw(boot_src, boot_instance);
+
+ reset_source_set(zynqmp_get_reset_src());
+
+ return 0;
+}
+postcore_initcall(zynqmp_init);