diff options
Diffstat (limited to 'arch/arm/mach-zynqmp')
-rw-r--r-- | arch/arm/mach-zynqmp/Kconfig | 19 | ||||
-rw-r--r-- | arch/arm/mach-zynqmp/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-zynqmp/firmware-zynqmp.c | 209 | ||||
-rw-r--r-- | arch/arm/mach-zynqmp/include/mach/debug_ll.h | 31 | ||||
-rw-r--r-- | arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h | 80 | ||||
-rw-r--r-- | arch/arm/mach-zynqmp/zynqmp-bbu.c | 14 | ||||
-rw-r--r-- | arch/arm/mach-zynqmp/zynqmp.c | 160 |
7 files changed, 392 insertions, 123 deletions
diff --git a/arch/arm/mach-zynqmp/Kconfig b/arch/arm/mach-zynqmp/Kconfig index c9dc71c9e7..23d04926e6 100644 --- a/arch/arm/mach-zynqmp/Kconfig +++ b/arch/arm/mach-zynqmp/Kconfig @@ -1,5 +1,14 @@ # SPDX-License-Identifier: GPL-2.0-or-later -if ARCH_ZYNQMP + +menu "ZynqMP Features" + depends on ARCH_ZYNQMP + +config MACH_XILINX_ZCU102 + bool "Xilinx Zynq UltraScale+ MPSoC ZCU102" + select ARM_USE_COMPRESSED_DTB + help + Say Y here if you are using the Xilinx Zynq UltraScale+ MPSoC ZCU102 + evaluation board. config MACH_XILINX_ZCU104 bool "Xilinx Zynq UltraScale+ MPSoC ZCU104" @@ -7,4 +16,10 @@ config MACH_XILINX_ZCU104 Say Y here if you are using the Xilinx Zynq UltraScale+ MPSoC ZCU104 evaluation board. -endif +config MACH_XILINX_ZCU106 + bool "Xilinx Zynq UltraScale+ MPSoC ZCU106" + help + Say Y here if you are using the Xilinx Zynq UltraScale+ MPSoC ZCU106 + evaluation board. + +endmenu 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/firmware-zynqmp.c b/arch/arm/mach-zynqmp/firmware-zynqmp.c index 6123aa1ea4..039a46e767 100644 --- a/arch/arm/mach-zynqmp/firmware-zynqmp.c +++ b/arch/arm/mach-zynqmp/firmware-zynqmp.c @@ -14,9 +14,17 @@ #include <common.h> #include <init.h> +#include <driver.h> +#include <param.h> #include <linux/arm-smccc.h> -#include <mach/firmware-zynqmp.h> +#include <mach/zynqmp/firmware-zynqmp.h> + +struct zynqmp_fw { + struct device *dev; + u32 ggs[4]; + u32 pggs[4]; +}; #define ZYNQMP_TZ_VERSION(MAJOR, MINOR) ((MAJOR << 16) | MINOR) @@ -40,6 +48,7 @@ enum pm_ret_status { enum pm_api_id { PM_GET_API_VERSION = 1, + PM_MMIO_WRITE = 19, PM_FPGA_LOAD = 22, PM_FPGA_GET_STATUS, PM_IOCTL = 34, @@ -504,6 +513,130 @@ static int zynqmp_pm_ioctl(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2, } /** + * zynqmp_pm_set_sd_tapdelay() - Set tap delay for the SD device + * + * @node_id: Node ID of the device + * @type: Type of tap delay to set (input/output) + * @value: Value to set fot the tap delay + * + * This function sets input/output tap delay for the SD device. + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_set_sd_tapdelay(u32 node_id, u32 type, u32 value) +{ + u32 reg = (type == PM_TAPDELAY_INPUT) ? SD_ITAPDLY : SD_OTAPDLYSEL; + u32 mask = (node_id == NODE_SD_0) ? GENMASK(15, 0) : GENMASK(31, 16); + + if (value) { + return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, + IOCTL_SET_SD_TAPDELAY, + type, value, NULL); + } + + /* + * Work around completely misdesigned firmware API on Xilinx ZynqMP. + * The IOCTL_SET_SD_TAPDELAY firmware call allows the caller to only + * ever set IOU_SLCR SD_ITAPDLY Register SD0_ITAPDLYENA/SD1_ITAPDLYENA + * bits, but there is no matching call to clear those bits. If those + * bits are not cleared, SDMMC tuning may fail. + * + * Luckily, there are PM_MMIO_READ/PM_MMIO_WRITE calls which seem to + * allow complete unrestricted access to all address space, including + * IOU_SLCR SD_ITAPDLY Register and all the other registers, access + * to which was supposed to be protected by the current firmware API. + * + * Use PM_MMIO_READ/PM_MMIO_WRITE to re-implement the missing counter + * part of IOCTL_SET_SD_TAPDELAY which clears SDx_ITAPDLYENA bits. + */ + return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, reg, mask, 0, 0, NULL); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_tapdelay); + +/** + * zynqmp_pm_sd_dll_reset() - Reset DLL logic + * + * @node_id: Node ID of the device + * @type: Reset type + * + * This function resets DLL logic for the SD device. + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_sd_dll_reset(u32 node_id, u32 type) +{ + return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, IOCTL_SD_DLL_RESET, + type, 0, NULL); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_sd_dll_reset); + +/* + * zynqmp_pm_write_ggs() - PM API for writing global general storage (ggs) + * @index: GGS register index + * @value: Register value to be written + * + * This function writes value to GGS register. + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_write_ggs(u32 index, u32 value) +{ + return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_WRITE_GGS, + index, value, NULL); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs); + +/** + * zynqmp_pm_read_ggs() - PM API for reading global general storage (ggs) + * @index: GGS register index + * @value: Register value to be written + * + * This function returns GGS register value. + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_read_ggs(u32 index, u32 *value) +{ + return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_READ_GGS, + index, 0, value); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_read_ggs); + +/** + * zynqmp_pm_write_pggs() - PM API for writing persistent global general + * storage (pggs) + * @index: PGGS register index + * @value: Register value to be written + * + * This function writes value to PGGS register. + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_write_pggs(u32 index, u32 value) +{ + return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_WRITE_PGGS, index, value, + NULL); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs); + +/** + * zynqmp_pm_read_pggs() - PM API for reading persistent global general + * storage (pggs) + * @index: PGGS register index + * @value: Register value to be written + * + * This function returns PGGS register value. + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_read_pggs(u32 index, u32 *value) +{ + return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_READ_PGGS, index, 0, + value); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_read_pggs); + +/** * zynqmp_pm_fpga_load - Perform the fpga load * @address: Address to write to * @size: pl bitstream size @@ -576,12 +709,59 @@ const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void) } EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops); +static bool parse_reg(const char *reg, unsigned *idx) +{ + bool pggs = reg[0] == 'p'; + kstrtouint(reg + pggs + sizeof("ggs") - 1, 10, idx); + return pggs; +} + +static int ggs_set(struct param_d *p, void *_val) +{ + u32 *val = _val; + unsigned idx; + + if (parse_reg(p->name, &idx)) + return zynqmp_pm_write_pggs(idx, *val); + else + return zynqmp_pm_write_ggs(idx, *val); +} +static int ggs_get(struct param_d *p, void *_val) +{ + u32 ret_payload[PAYLOAD_ARG_CNT]; + u32 *val = _val; + unsigned idx; + int ret; + + if (parse_reg(p->name, &idx)) + ret = zynqmp_pm_read_pggs(idx, ret_payload); + else + ret = zynqmp_pm_read_ggs(idx, ret_payload); + + if (ret) + return ret; -static int zynqmp_firmware_probe(struct device_d *dev) + *val = ret_payload[1]; + + return 0; +} + +static inline void dev_add_param_ggs(struct zynqmp_fw *fw, const char *str, u32 *value) { + dev_add_param_uint32(fw->dev, str, ggs_set, ggs_get, value, "0x%x", value); +} + +static int zynqmp_firmware_probe(struct device *dev) +{ + + struct zynqmp_fw *fw; int ret; - ret = get_set_conduit_method(dev->device_node); + fw = xzalloc(sizeof(*fw)); + + dev_add_alias(dev, "zynqmp_fw"); + + ret = get_set_conduit_method(dev->of_node); if (ret) goto out; @@ -619,7 +799,19 @@ static int zynqmp_firmware_probe(struct device_d *dev) dev_dbg(dev, "Trustzone version v%d.%d\n", pm_tz_version >> 16, pm_tz_version & 0xFFFF); - of_platform_populate(dev->device_node, NULL, dev); + of_platform_populate(dev->of_node, NULL, dev); + + fw->dev = dev; + + dev_add_param_ggs(fw, "ggs0", &fw->ggs[0]); + dev_add_param_ggs(fw, "ggs1", &fw->ggs[1]); + dev_add_param_ggs(fw, "ggs2", &fw->ggs[2]); + dev_add_param_ggs(fw, "ggs3", &fw->ggs[3]); + + dev_add_param_ggs(fw, "pggs0", &fw->pggs[0]); + dev_add_param_ggs(fw, "pggs1", &fw->pggs[1]); + dev_add_param_ggs(fw, "pggs2", &fw->pggs[2]); + dev_add_param_ggs(fw, "pggs3", &fw->pggs[3]); out: if (ret) do_fw_call = do_fw_call_fail; @@ -630,15 +822,12 @@ static struct of_device_id zynqmp_firmware_id_table[] = { { .compatible = "xlnx,zynqmp-firmware", }, {} }; +MODULE_DEVICE_TABLE(of, zynqmp_firmware_id_table); -static struct driver_d zynqmp_firmware_driver = { +static struct driver zynqmp_firmware_driver = { .name = "zynqmp_firmware", .probe = zynqmp_firmware_probe, .of_compatible = DRV_OF_COMPAT(zynqmp_firmware_id_table), }; -static int zynqmp_firmware_init(void) -{ - return platform_driver_register(&zynqmp_firmware_driver); -} -core_initcall(zynqmp_firmware_init); +core_platform_driver(zynqmp_firmware_driver); diff --git a/arch/arm/mach-zynqmp/include/mach/debug_ll.h b/arch/arm/mach-zynqmp/include/mach/debug_ll.h deleted file mode 100644 index 67571fe2e1..0000000000 --- a/arch/arm/mach-zynqmp/include/mach/debug_ll.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef __MACH_DEBUG_LL_H__ -#define __MACH_DEBUG_LL_H__ - -#include <io.h> - -#define ZYNQMP_UART0_BASE 0xFF000000 -#define ZYNQMP_UART1_BASE 0xFF010000 -#define ZYNQMP_UART_BASE ZYNQMP_UART0_BASE -#define ZYNQMP_DEBUG_LL_UART_BASE ZYNQMP_UART_BASE - -#define ZYNQMP_UART_RXTXFIFO 0x30 -#define ZYNQMP_UART_CHANNEL_STS 0x2C - -#define ZYNQMP_UART_STS_TFUL (1 << 4) -#define ZYNQMP_UART_TXDIS (1 << 5) - -static inline void PUTC_LL(int c) -{ - void __iomem *base = (void __iomem *)ZYNQMP_DEBUG_LL_UART_BASE; - - if (readl(base) & ZYNQMP_UART_TXDIS) - return; - - while ((readl(base + ZYNQMP_UART_CHANNEL_STS) & ZYNQMP_UART_STS_TFUL) != 0) - ; - - writel(c, base + 0x30); -} - -#endif diff --git a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h deleted file mode 100644 index a04482237d..0000000000 --- a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h +++ /dev/null @@ -1,80 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Xilinx Zynq MPSoC Firmware layer - * - * Copyright (c) 2018 Thomas Haemmerle <thomas.haemmerle@wolfvision.net> - * - * based on Linux xlnx-zynqmp - * - * Michal Simek <michal.simek@xilinx.com> - * Davorin Mista <davorin.mista@aggios.com> - * Jolly Shah <jollys@xilinx.com> - * Rajan Vaja <rajanv@xilinx.com> - */ - -#ifndef FIRMWARE_ZYNQMP_H_ -#define FIRMWARE_ZYNQMP_H_ - -#define PAYLOAD_ARG_CNT 4 - -#define ZYNQMP_PM_VERSION(MAJOR, MINOR) ((MAJOR << 16) | MINOR) - -#define ZYNQMP_FPGA_BIT_AUTH_DDR BIT(1) -#define ZYNQMP_FPGA_BIT_AUTH_OCM BIT(2) -#define ZYNQMP_FPGA_BIT_ENC_USR_KEY BIT(3) -#define ZYNQMP_FPGA_BIT_ENC_DEV_KEY BIT(4) -#define ZYNQMP_FPGA_BIT_ONLY_BIN BIT(5) - -#define ZYNQMP_PCAP_STATUS_FPGA_DONE BIT(3) - -enum pm_ioctl_id { - IOCTL_SET_PLL_FRAC_MODE = 8, - IOCTL_GET_PLL_FRAC_MODE, - IOCTL_SET_PLL_FRAC_DATA, - IOCTL_GET_PLL_FRAC_DATA, -}; - -enum pm_query_id { - PM_QID_INVALID, - PM_QID_CLOCK_GET_NAME, - PM_QID_CLOCK_GET_TOPOLOGY, - PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS, - PM_QID_CLOCK_GET_PARENTS, - PM_QID_CLOCK_GET_ATTRIBUTES, - PM_QID_CLOCK_GET_NUM_CLOCKS = 12, -}; - -/** - * struct zynqmp_pm_query_data - PM query data - * @qid: query ID - * @arg1: Argument 1 of query data - * @arg2: Argument 2 of query data - * @arg3: Argument 3 of query data - */ -struct zynqmp_pm_query_data { - u32 qid; - u32 arg1; - u32 arg2; - u32 arg3; -}; - -struct zynqmp_eemi_ops { - int (*get_api_version)(u32 *version); - int (*query_data)(struct zynqmp_pm_query_data qdata, u32 *out); - int (*clock_enable)(u32 clock_id); - int (*clock_disable)(u32 clock_id); - int (*clock_getstate)(u32 clock_id, u32 *state); - int (*clock_setdivider)(u32 clock_id, u32 divider); - int (*clock_getdivider)(u32 clock_id, u32 *divider); - int (*clock_setrate)(u32 clock_id, u64 rate); - int (*clock_getrate)(u32 clock_id, u64 *rate); - int (*clock_setparent)(u32 clock_id, u32 parent_id); - int (*clock_getparent)(u32 clock_id, u32 *parent_id); - int (*ioctl)(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2, u32 *out); - int (*fpga_getstatus)(u32 *status); - int (*fpga_load)(u64 address, u32 size, u32 flags); -}; - -const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void); - -#endif /* FIRMWARE_ZYNQMP_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..3c5e2fe885 --- /dev/null +++ b/arch/arm/mach-zynqmp/zynqmp-bbu.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020 Michael Tretter <m.tretter@pengutronix.de> + */ + +#include <common.h> +#include <mach/zynqmp/zynqmp-bbu.h> + +int zynqmp_bbu_register_handler(const char *name, char *devicefile, + unsigned long flags) +{ + return bbu_register_std_file_update(name, flags, devicefile, + filetype_zynq_image); +} 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); |