Add a driver for simple reset controllers, where each reset line is controlled by a single bit in a memory-mapped register range.
The implementation is derived from the Linux reset-simple driver. The controller logic itself is generic; the driver currently matches the Metanoia MT2824 instance and further controllers can be supported by adding their compatible to the match table. Signed-off-by: Benoît Monin <[email protected]> --- MAINTAINERS | 5 ++ drivers/reset/Kconfig | 8 +++ drivers/reset/Makefile | 1 + drivers/reset/reset-simple.c | 115 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index eb4209bdea6..aed0dcc515a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1570,6 +1570,11 @@ S: Maintained T: git https://git.u-boot-project.org/u-boot/custodians/u-boot-nand-flash.git F: drivers/mtd/nand/raw/ +RESET SIMPLE DRIVER +M: Benoît Monin <[email protected]> +S: Maintained +F: drivers/reset/reset-simple.c + RISC-V M: Tim Ouyang <[email protected]> M: Leo Liang <[email protected]> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index db764ed5ace..be178125be6 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -149,6 +149,14 @@ config RESET_MESON help Support for reset controller on Amlogic Meson SoC. +config RESET_SIMPLE + bool "Generic driver for simple reset controller" + depends on DM_RESET + help + This enables the reset driver for simple controllers where + each reset line is controlled by a single bit in a memory + mapped region. + config RESET_SOCFPGA bool "Reset controller driver for SoCFPGA" depends on DM_RESET && ARCH_SOCFPGA diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 384f4336331..553260a71e8 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_RESET_AST2600) += reset-ast2600.o obj-$(CONFIG_RESET_AST2700) += reset-ast2700.o obj-$(CONFIG_$(PHASE_)RESET_ROCKCHIP) += reset-rockchip.o rst-rk3506.o rst-rk3528.o rst-rk3576.o rst-rk3588.o obj-$(CONFIG_RESET_MESON) += reset-meson.o +obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_RESET_MEDIATEK) += reset-mediatek.o obj-$(CONFIG_RESET_MTMIPS) += reset-mtmips.o diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c new file mode 100644 index 00000000000..5df16a341d4 --- /dev/null +++ b/drivers/reset/reset-simple.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Simple Reset Controller Driver + * + * Based on Linux reset-simple driver + */ + +#include <dm.h> +#include <reset-uclass.h> +#include <linux/io.h> + +struct reset_simple_priv { + void __iomem *membase; + int nr_resets; +}; + +static int reset_simple_update(struct reset_ctl *rst, bool assert) +{ + struct reset_simple_priv *priv = dev_get_priv(rst->dev); + int reg_width = sizeof(u32); + int bank, offset; + u32 reg; + + if (rst->id >= priv->nr_resets) + 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 reset_simple_request(struct reset_ctl *rst) +{ + struct reset_simple_priv *priv = dev_get_priv(rst->dev); + + if (rst->id >= priv->nr_resets) + return -EINVAL; + + return 0; +} + +static int reset_simple_assert(struct reset_ctl *rst) +{ + return reset_simple_update(rst, true); +} + +static int reset_simple_deassert(struct reset_ctl *rst) +{ + return reset_simple_update(rst, false); +} + +static int reset_simple_status(struct reset_ctl *rst) +{ + struct reset_simple_priv *priv = dev_get_priv(rst->dev); + int reg_width = sizeof(u32); + int bank, offset; + u32 reg; + + if (rst->id >= priv->nr_resets) + 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)); + + return !!(reg & BIT(offset)); +} + +static const struct reset_ops reset_simple_ops = { + .request = reset_simple_request, + .rst_assert = reset_simple_assert, + .rst_deassert = reset_simple_deassert, + .rst_status = reset_simple_status, +}; + +static const struct udevice_id reset_simple_ids[] = { + { .compatible = "metanoia,mt2824-reset" }, + { } +}; + +static int reset_simple_probe(struct udevice *dev) +{ + struct reset_simple_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + fdt_size_t size; + + addr = dev_read_addr_size_index(dev, 0, &size); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->nr_resets = size * BITS_PER_BYTE; + + priv->membase = devm_ioremap(dev, addr, size); + if (!priv->membase) + return -EFAULT; + + return 0; +} + +U_BOOT_DRIVER(reset_simple) = { + .name = "simple-reset", + .id = UCLASS_RESET, + .of_match = reset_simple_ids, + .ops = &reset_simple_ops, + .probe = reset_simple_probe, + .priv_auto = sizeof(struct reset_simple_priv), +}; -- 2.55.0
