From patchwork Sat Jan 25 12:22:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amit Tomer X-Patchwork-Id: 240099 List-Id: U-Boot discussion From: amittomer25 at gmail.com (Amit Singh Tomar) Date: Sat, 25 Jan 2020 17:52:57 +0530 Subject: [PATCH v3 15/21] reset: add driver for generic reset controllers In-Reply-To: <1579954983-11329-1-git-send-email-amittomer25@gmail.com> References: <1579954983-11329-1-git-send-email-amittomer25@gmail.com> Message-ID: <1579954983-11329-16-git-send-email-amittomer25@gmail.com> The simplest and most generic form of a reset controller just exposes multiple MMIO registers, where each bit toggles a separate reset line. Add a generic driver to describe this kind of reset controller. This is used on the Action Semi S700, for instance, but also by other SoCs. Signed-off-by: Amit Singh Tomar [Andre: make more generic, let it cover multiple registers, slight rework] Signed-off-by: Andre Przywara --- Changes since v2: * Newly added patch, not there in v2/v1. --- drivers/reset/Kconfig | 6 +++ drivers/reset/Makefile | 1 + drivers/reset/reset-generic.c | 111 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 drivers/reset/reset-generic.c diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 75ccd65..1cdc159 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -12,6 +12,12 @@ config DM_RESET although driving such reset isgnals using GPIOs may be more appropriate in this case. +config GENERIC_RESET + bool "Generic Reset controller driver" + depends on DM_RESET + help + Support Generic reset controller. + config SANDBOX_RESET bool "Enable the sandbox reset test driver" depends on DM_MAILBOX && SANDBOX diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 0a044d5..5e027a1 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -4,6 +4,7 @@ # obj-$(CONFIG_DM_RESET) += reset-uclass.o +obj-$(CONFIG_GENERIC_RESET) += reset-generic.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-reset.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-reset-test.o obj-$(CONFIG_STI_RESET) += sti-reset.o diff --git a/drivers/reset/reset-generic.c b/drivers/reset/reset-generic.c new file mode 100644 index 0000000..9c45087 --- /dev/null +++ b/drivers/reset/reset-generic.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2017 Amit Singh Tomar + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct generic_reset_priv { + void __iomem *membase; + int max_reset; +}; + +#define BITS_PER_BYTE 8 +static int generic_reset_toggle(struct reset_ctl *rst, bool assert) +{ + struct generic_reset_priv *priv = dev_get_priv(rst->dev); + int reg_width = sizeof(u32); + int bank, offset; + u32 reg; + + if (rst->id >= priv->max_reset) + return -EINVAL; + + bank = rst->id / (reg_width * BITS_PER_BYTE); + offset = rst->id % (reg_width * BITS_PER_BYTE); + + reg = readl(priv->membase + (bank * reg_width)); + if (assert) + writel(reg & ~BIT(offset), priv->membase + (bank * reg_width)); + else + writel(reg | BIT(offset), priv->membase + (bank * reg_width)); + + return 0; +} + +static int generic_reset_assert(struct reset_ctl *rst) +{ + return generic_reset_toggle(rst, true); +} + +static int generic_reset_deassert(struct reset_ctl *rst) +{ + return generic_reset_toggle(rst, false); +} + +static int generic_reset_free(struct reset_ctl *rst) +{ + return 0; +} + +static int generic_reset_request(struct reset_ctl *rst) +{ + struct generic_reset_priv *priv = dev_get_priv(rst->dev); + + if (rst->id >= priv->max_reset) + return -EINVAL; + + return generic_reset_assert(rst); +} + +struct reset_ops generic_reset_reset_ops = { + .free = generic_reset_free, + .request = generic_reset_request, + .rst_assert = generic_reset_assert, + .rst_deassert = generic_reset_deassert, +}; + +static const struct udevice_id generic_reset_ids[] = { + { .compatible = "generic-reset" }, + { .compatible = "actions,s700-reset" }, + { } +}; + +static int generic_reset_probe(struct udevice *dev) +{ + struct generic_reset_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + fdt_size_t size; + + addr = devfdt_get_addr_size_index(dev, 0, &size); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->max_reset = dev_read_u32_default(dev, "num-resets", -1); + if (priv->max_reset == -1) + priv->max_reset = size * BITS_PER_BYTE; + + priv->membase = devm_ioremap(dev, addr, size); + if (!priv->membase) + return -EFAULT; + + return 0; +} + +U_BOOT_DRIVER(generic_reset) = { + .name = "generic_reset", + .id = UCLASS_RESET, + .of_match = generic_reset_ids, + .ops = &generic_reset_reset_ops, + .probe = generic_reset_probe, + .priv_auto_alloc_size = sizeof(struct generic_reset_priv), +};