[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250922-dr1v90-cru-v1-4-e393d758de4e@pigmoral.tech>
Date: Mon, 22 Sep 2025 22:51:50 +0800
From: Junhui Liu <junhui.liu@...moral.tech>
To: Michael Turquette <mturquette@...libre.com>,
Stephen Boyd <sboyd@...nel.org>, Rob Herring <robh@...nel.org>,
Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>, Junhui Liu <junhui.liu@...moral.tech>,
Philipp Zabel <p.zabel@...gutronix.de>,
Paul Walmsley <paul.walmsley@...ive.com>,
Palmer Dabbelt <palmer@...belt.com>, Albert Ou <aou@...s.berkeley.edu>,
Alexandre Ghiti <alex@...ti.fr>
Cc: linux-clk@...r.kernel.org, linux-kernel@...r.kernel.org,
devicetree@...r.kernel.org, linux-riscv@...ts.infradead.org,
"fushan.zeng" <fushan.zeng@...ogic.com>
Subject: [PATCH 4/5] reset: anlogic: add support for Anlogic DR1V90 resets
Add reset controller support for the Anlogic DR1V90 SoC, which is an
auxiliary device associated with the Clock and Reset Unit (CRU). All
resets are active-low.
Signed-off-by: Junhui Liu <junhui.liu@...moral.tech>
---
drivers/reset/Kconfig | 9 +++
drivers/reset/Makefile | 1 +
drivers/reset/reset-dr1v90.c | 136 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 146 insertions(+)
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 635eef469ab797ac8ef39d95a82d47071aeec630..bc7a1abb907806a1efaf568ee3dc3ca6081f667b 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -66,6 +66,15 @@ config RESET_BRCMSTB_RESCAL
This enables the RESCAL reset controller for SATA, PCIe0, or PCIe1 on
BCM7216 or the BCM2712.
+config RESET_DR1V90
+ tristate "Anlogic DR1V90 reset controller"
+ depends on ARCH_ANLOGIC || COMPILE_TEST
+ select AUXILIARY_BUS
+ default ARCH_ANLOGIC
+ help
+ This enables the reset controller driver for Anlogic DR1V90 SoCs
+ provided by the CRU unit.
+
config RESET_EYEQ
bool "Mobileye EyeQ reset controller"
depends on MACH_EYEQ5 || MACH_EYEQ6H || COMPILE_TEST
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index a917d2522e8d12af0dd2b252e493fa4fc9eabecf..441307fd6ccd6fe0793fe819a60e66888efcb92c 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o
obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o
obj-$(CONFIG_RESET_BRCMSTB) += reset-brcmstb.o
obj-$(CONFIG_RESET_BRCMSTB_RESCAL) += reset-brcmstb-rescal.o
+obj-$(CONFIG_RESET_DR1V90) += reset-dr1v90.o
obj-$(CONFIG_RESET_EYEQ) += reset-eyeq.o
obj-$(CONFIG_RESET_GPIO) += reset-gpio.o
obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o
diff --git a/drivers/reset/reset-dr1v90.c b/drivers/reset/reset-dr1v90.c
new file mode 100644
index 0000000000000000000000000000000000000000..914bbb9331969939f039bfb3caa6ef9d88a48b96
--- /dev/null
+++ b/drivers/reset/reset-dr1v90.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2025 Shanghai Anlogic Infotech Co., Ltd.
+ * Copyright (c) 2025 Junhui Liu <junhui.liu@...moral.tech>
+ */
+
+#include <linux/auxiliary_bus.h>
+#include "linux/device.h"
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/reset/anlogic,dr1v90-cru.h>
+
+struct dr1v90_reset_map {
+ u32 offset;
+ u32 bit;
+};
+
+struct dr1v90_reset_controller {
+ struct reset_controller_dev rcdev;
+ void __iomem *base;
+};
+
+static inline struct dr1v90_reset_controller *
+to_dr1v90_reset_controller(struct reset_controller_dev *rcdev)
+{
+ return container_of(rcdev, struct dr1v90_reset_controller, rcdev);
+}
+
+static const struct dr1v90_reset_map dr1v90_resets[] = {
+ [RESET_OCM] = { 0x74, BIT(4)},
+ [RESET_QSPI] = { 0x74, BIT(5)},
+ [RESET_SMC] = { 0x74, BIT(6)},
+ [RESET_WDT] = { 0x74, BIT(7)},
+ [RESET_DMAC_AXI] = { 0x74, BIT(8)},
+ [RESET_DMAC_AHB] = { 0x74, BIT(9)},
+ [RESET_NPU] = { 0x74, BIT(12)},
+ [RESET_JPU] = { 0x74, BIT(13)},
+ [RESET_DDRBUS] = { 0x74, BIT(14)},
+ [RESET_NIC_HP0] = { 0x78, BIT(0)},
+ [RESET_NIC_HP1] = { 0x78, BIT(1)},
+ [RESET_NIC_GP0M] = { 0x78, BIT(4)},
+ [RESET_NIC_GP1M] = { 0x78, BIT(5)},
+ [RESET_GPIO] = { 0x78, BIT(8)},
+ [RESET_IPC] = { 0x78, BIT(12)},
+ [RESET_USB0] = { 0x7C, BIT(0)},
+ [RESET_USB1] = { 0x7C, BIT(1)},
+ [RESET_GBE0] = { 0x7C, BIT(4)},
+ [RESET_GBE1] = { 0x7C, BIT(5)},
+ [RESET_SDIO0] = { 0x7C, BIT(8)},
+ [RESET_SDIO1] = { 0x7C, BIT(9)},
+ [RESET_UART0] = { 0x7C, BIT(12)},
+ [RESET_UART1] = { 0x7C, BIT(13)},
+ [RESET_SPI0] = { 0x7C, BIT(16)},
+ [RESET_SPI1] = { 0x7C, BIT(17)},
+ [RESET_CAN0] = { 0x7C, BIT(20)},
+ [RESET_CAN1] = { 0x7C, BIT(21)},
+ [RESET_TTC0] = { 0x7C, BIT(24)},
+ [RESET_TTC1] = { 0x7C, BIT(25)},
+ [RESET_I2C0] = { 0x7C, BIT(28)},
+ [RESET_I2C1] = { 0x7C, BIT(29)}
+};
+
+static int dr1v90_reset_control_update(struct reset_controller_dev *rcdev,
+ unsigned long id, bool assert)
+{
+ struct dr1v90_reset_controller *rstc = to_dr1v90_reset_controller(rcdev);
+ u32 offset = dr1v90_resets[id].offset;
+ u32 bit = dr1v90_resets[id].bit;
+ u32 reg;
+
+ reg = readl(rstc->base + offset);
+ if (assert)
+ reg &= ~bit;
+ else
+ reg |= bit;
+ writel(reg, rstc->base + offset);
+
+ return 0;
+}
+
+static int dr1v90_reset_control_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return dr1v90_reset_control_update(rcdev, id, true);
+}
+
+static int dr1v90_reset_control_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return dr1v90_reset_control_update(rcdev, id, false);
+}
+
+static const struct reset_control_ops dr1v90_reset_control_ops = {
+ .assert = dr1v90_reset_control_assert,
+ .deassert = dr1v90_reset_control_deassert,
+};
+
+static int dr1v90_reset_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+{
+ struct dr1v90_reset_controller *rstc;
+ struct device *dev = &adev->dev;
+
+ rstc = devm_kzalloc(dev, sizeof(*rstc), GFP_KERNEL);
+ if (!rstc)
+ return -ENOMEM;
+
+ rstc->base = of_iomap(dev->parent->of_node, 0);
+ rstc->rcdev.dev = dev;
+ rstc->rcdev.nr_resets = ARRAY_SIZE(dr1v90_resets);
+ rstc->rcdev.of_node = dev->parent->of_node;
+ rstc->rcdev.ops = &dr1v90_reset_control_ops;
+ rstc->rcdev.owner = THIS_MODULE;
+
+ return devm_reset_controller_register(dev, &rstc->rcdev);
+}
+
+static const struct auxiliary_device_id dr1v90_reset_ids[] = {
+ {
+ .name = "anlogic_dr1v90_cru.reset"
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(auxiliary, dr1v90_reset_ids);
+
+static struct auxiliary_driver dr1v90_reset_driver = {
+ .probe = dr1v90_reset_probe,
+ .id_table = dr1v90_reset_ids,
+};
+module_auxiliary_driver(dr1v90_reset_driver);
+
+MODULE_AUTHOR("Junhui Liu <junhui.liu@...moral.tech>");
+MODULE_DESCRIPTION("Anlogic DR1V90 reset controller driver");
+MODULE_LICENSE("GPL");
--
2.51.0
Powered by blists - more mailing lists