diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/reset/Kconfig | 9 | ||||
-rw-r--r-- | drivers/reset/Makefile | 1 | ||||
-rw-r--r-- | drivers/reset/reset-zynqmp.c | 100 |
3 files changed, 110 insertions, 0 deletions
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index a42b3f0077..d73daf5e31 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -197,4 +197,13 @@ config RESET_SCMI Enable this option if you want to support reset controller devices exposed by a SCMI agent based on SCMI reset domain protocol communication with a SCMI server. + +config RESET_ZYNQMP + bool "Reset Driver for Xilinx ZynqMP SoC's" + depends on DM_RESET && ZYNQMP_FIRMWARE + help + Support for reset controller on Xilinx ZynqMP SoC. Driver is only + passing request via Xilinx firmware interface to TF-A and PMU + firmware. + endmenu diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 8a0f528076..d69486bdeb 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_RESET_SIFIVE) += reset-sifive.o obj-$(CONFIG_RESET_SYSCON) += reset-syscon.o obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o obj-$(CONFIG_RESET_SCMI) += reset-scmi.o +obj-$(CONFIG_RESET_ZYNQMP) += reset-zynqmp.o diff --git a/drivers/reset/reset-zynqmp.c b/drivers/reset/reset-zynqmp.c new file mode 100644 index 0000000000..5765234673 --- /dev/null +++ b/drivers/reset/reset-zynqmp.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Xilinx, Inc. - Michal Simek + */ + +#define LOG_CATEGORY UCLASS_RESET + +#include <common.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <reset-uclass.h> +#include <zynqmp_firmware.h> + +#define ZYNQMP_NR_RESETS (ZYNQMP_PM_RESET_END - ZYNQMP_PM_RESET_START) +#define ZYNQMP_RESET_ID ZYNQMP_PM_RESET_START + +struct zynqmp_reset_priv { + u32 reset_id; + u32 nr_reset; +}; + +static int zynqmp_pm_reset_assert(const u32 reset, + const enum zynqmp_pm_reset_action assert_flag) +{ + return xilinx_pm_request(PM_RESET_ASSERT, reset, assert_flag, 0, 0, + NULL); +} + +static int zynqmp_reset_assert(struct reset_ctl *rst) +{ + struct zynqmp_reset_priv *priv = dev_get_priv(rst->dev); + + dev_dbg(rst->dev, "%s(rst=%p) (id=%lu)\n", __func__, rst, rst->id); + + return zynqmp_pm_reset_assert(priv->reset_id + rst->id, + PM_RESET_ACTION_ASSERT); +} + +static int zynqmp_reset_deassert(struct reset_ctl *rst) +{ + struct zynqmp_reset_priv *priv = dev_get_priv(rst->dev); + + dev_dbg(rst->dev, "%s(rst=%p) (id=%lu)\n", __func__, rst, rst->id); + + return zynqmp_pm_reset_assert(priv->reset_id + rst->id, + PM_RESET_ACTION_RELEASE); +} + +static int zynqmp_reset_request(struct reset_ctl *rst) +{ + struct zynqmp_reset_priv *priv = dev_get_priv(rst->dev); + + dev_dbg(rst->dev, "%s(rst=%p) (id=%lu) (nr_reset=%d)\n", __func__, + rst, rst->id, priv->nr_reset); + + if (rst->id > priv->nr_reset) + return -EINVAL; + + return 0; +} + +static int zynqmp_reset_free(struct reset_ctl *rst) +{ + struct zynqmp_reset_priv *priv = dev_get_priv(rst->dev); + + dev_dbg(rst->dev, "%s(rst=%p) (id=%lu) (nr_reset=%d)\n", __func__, + rst, rst->id, priv->nr_reset); + + return 0; +} + +static int zynqmp_reset_probe(struct udevice *dev) +{ + struct zynqmp_reset_priv *priv = dev_get_priv(dev); + + priv->reset_id = ZYNQMP_RESET_ID; + priv->nr_reset = ZYNQMP_NR_RESETS; + return 0; +} + +const struct reset_ops zynqmp_reset_ops = { + .request = zynqmp_reset_request, + .rfree = zynqmp_reset_free, + .rst_assert = zynqmp_reset_assert, + .rst_deassert = zynqmp_reset_deassert, +}; + +static const struct udevice_id zynqmp_reset_ids[] = { + { .compatible = "xlnx,zynqmp-reset" }, + { } +}; + +U_BOOT_DRIVER(zynqmp_reset) = { + .name = "zynqmp_reset", + .id = UCLASS_RESET, + .of_match = zynqmp_reset_ids, + .ops = &zynqmp_reset_ops, + .probe = zynqmp_reset_probe, + .priv_auto = sizeof(struct zynqmp_reset_priv), +}; |