]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
reset: tenstorrent: Add reset controller for Atlantis
authorAnirudh Srinivasan <asrinivasan@oss.tenstorrent.com>
Fri, 6 Mar 2026 17:12:18 +0000 (11:12 -0600)
committerDrew Fustini <fustini@kernel.org>
Tue, 10 Mar 2026 03:10:26 +0000 (20:10 -0700)
Adds Atlantis Reset Controller driver, which shares the same regmap as
prcm ( clock controller).

This version of the reset controller driver covers resets from the RCPU
prcm.

Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Anirudh Srinivasan <asrinivasan@oss.tenstorrent.com>
Reviewed-by: Drew Fustini <fustini@kernel.org>
Signed-off-by: Drew Fustini <fustini@kernel.org>
MAINTAINERS
drivers/reset/Kconfig
drivers/reset/Makefile
drivers/reset/reset-tenstorrent-atlantis.c [new file with mode: 0644]

index 40c179c8de1eae98dd1bf8eafa49dbd4354175da..493d007d3c650f26d1b57aff2f8a0a13955a3724 100644 (file)
@@ -22812,6 +22812,7 @@ T:      git https://github.com/tenstorrent/linux.git
 F:     Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml
 F:     Documentation/devicetree/bindings/riscv/tenstorrent.yaml
 F:     arch/riscv/boot/dts/tenstorrent/
+F:     drivers/reset/reset-tenstorrent-atlantis.c
 F:     include/dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h
 
 RISC-V THEAD SoC SUPPORT
index 7ce151f6a7e4d675f8556e8595c77fc2ce0bcd1b..85ee9da809eebe07f12ee7cd7ab9c55d053f780b 100644 (file)
@@ -315,6 +315,17 @@ config RESET_SUNXI
        help
          This enables the reset driver for Allwinner SoCs.
 
+config RESET_TENSTORRENT_ATLANTIS
+       tristate "Tenstorrent atlantis reset driver"
+       depends on ARCH_TENSTORRENT || COMPILE_TEST
+       select AUXILIARY_BUS
+       default ARCH_TENSTORRENT
+       help
+         This enables the driver for the reset controller
+         present in the Tenstorrent Atlantis SoC.
+         Enable this option to be able to use hardware
+         resets on Atalantis based systems.
+
 config RESET_TH1520
        tristate "T-HEAD TH1520 reset controller"
        depends on ARCH_THEAD || COMPILE_TEST
index fc0cc99f8514cac161af59389ba1cbd5490209c8..7c086baeb02a8abd2b8487398532f27c890e558c 100644 (file)
@@ -41,6 +41,7 @@ obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
 obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
 obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o
 obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
+obj-$(CONFIG_RESET_TENSTORRENT_ATLANTIS) += reset-tenstorrent-atlantis.o
 obj-$(CONFIG_RESET_TH1520) += reset-th1520.o
 obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
 obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o
diff --git a/drivers/reset/reset-tenstorrent-atlantis.c b/drivers/reset/reset-tenstorrent-atlantis.c
new file mode 100644 (file)
index 0000000..ab8be52
--- /dev/null
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Tenstorrent Atlantis PRCM Reset Driver
+ *
+ * Copyright (c) 2026 Tenstorrent
+ */
+
+#include <dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h>
+#include <linux/auxiliary_bus.h>
+#include <linux/reset-controller.h>
+#include <linux/regmap.h>
+
+/* RCPU Reset Register Offsets */
+#define RCPU_BLK_RST_REG 0x001c
+#define LSIO_BLK_RST_REG 0x0020
+#define HSIO_BLK_RST_REG 0x000c
+#define PCIE_SUBS_RST_REG 0x0000
+#define MM_RSTN_REG 0x0014
+
+struct atlantis_reset_data {
+       u8 bit;
+       u16 reg;
+       bool active_low;
+};
+
+struct atlantis_reset_controller_data {
+       const struct atlantis_reset_data *reset_data;
+       size_t count;
+};
+
+struct atlantis_reset_controller {
+       struct reset_controller_dev rcdev;
+       const struct atlantis_reset_controller_data *data;
+       struct regmap *regmap;
+};
+
+static inline struct atlantis_reset_controller *
+to_atlantis_reset_controller(struct reset_controller_dev *rcdev)
+{
+       return container_of(rcdev, struct atlantis_reset_controller, rcdev);
+}
+
+#define RESET_DATA(_reg, _bit, _active_low)                          \
+       {                                                            \
+               .bit = _bit, .reg = _reg, .active_low = _active_low, \
+       }
+
+static const struct atlantis_reset_data atlantis_rcpu_resets[] = {
+       [RST_SMNDMA0]   = RESET_DATA(RCPU_BLK_RST_REG, 0, true),
+       [RST_SMNDMA1]   = RESET_DATA(RCPU_BLK_RST_REG, 1, true),
+       [RST_WDT0]      = RESET_DATA(RCPU_BLK_RST_REG, 2, true),
+       [RST_WDT1]      = RESET_DATA(RCPU_BLK_RST_REG, 3, true),
+       [RST_TMR]       = RESET_DATA(RCPU_BLK_RST_REG, 4, true),
+       [RST_PVTC]      = RESET_DATA(RCPU_BLK_RST_REG, 12, true),
+       [RST_PMU]       = RESET_DATA(RCPU_BLK_RST_REG, 13, true),
+       [RST_MAILBOX]   = RESET_DATA(RCPU_BLK_RST_REG, 14, true),
+       [RST_SPACC]     = RESET_DATA(RCPU_BLK_RST_REG, 26, true),
+       [RST_OTP]       = RESET_DATA(RCPU_BLK_RST_REG, 28, true),
+       [RST_TRNG]      = RESET_DATA(RCPU_BLK_RST_REG, 29, true),
+       [RST_CRC]       = RESET_DATA(RCPU_BLK_RST_REG, 30, true),
+       [RST_QSPI]      = RESET_DATA(LSIO_BLK_RST_REG, 0, true),
+       [RST_I2C0]      = RESET_DATA(LSIO_BLK_RST_REG, 1, true),
+       [RST_I2C1]      = RESET_DATA(LSIO_BLK_RST_REG, 2, true),
+       [RST_I2C2]      = RESET_DATA(LSIO_BLK_RST_REG, 3, true),
+       [RST_I2C3]      = RESET_DATA(LSIO_BLK_RST_REG, 4, true),
+       [RST_I2C4]      = RESET_DATA(LSIO_BLK_RST_REG, 5, true),
+       [RST_UART0]     = RESET_DATA(LSIO_BLK_RST_REG, 6, true),
+       [RST_UART1]     = RESET_DATA(LSIO_BLK_RST_REG, 7, true),
+       [RST_UART2]     = RESET_DATA(LSIO_BLK_RST_REG, 8, true),
+       [RST_UART3]     = RESET_DATA(LSIO_BLK_RST_REG, 9, true),
+       [RST_UART4]     = RESET_DATA(LSIO_BLK_RST_REG, 10, true),
+       [RST_SPI0]      = RESET_DATA(LSIO_BLK_RST_REG, 11, true),
+       [RST_SPI1]      = RESET_DATA(LSIO_BLK_RST_REG, 12, true),
+       [RST_SPI2]      = RESET_DATA(LSIO_BLK_RST_REG, 13, true),
+       [RST_SPI3]      = RESET_DATA(LSIO_BLK_RST_REG, 14, true),
+       [RST_GPIO]      = RESET_DATA(LSIO_BLK_RST_REG, 15, true),
+       [RST_CAN0]      = RESET_DATA(LSIO_BLK_RST_REG, 17, true),
+       [RST_CAN1]      = RESET_DATA(LSIO_BLK_RST_REG, 18, true),
+       [RST_I2S0]      = RESET_DATA(LSIO_BLK_RST_REG, 19, true),
+       [RST_I2S1]      = RESET_DATA(LSIO_BLK_RST_REG, 20, true),
+
+};
+
+static const struct atlantis_reset_controller_data atlantis_rcpu_reset_data = {
+       .reset_data = atlantis_rcpu_resets,
+       .count = ARRAY_SIZE(atlantis_rcpu_resets),
+};
+
+static int atlantis_reset_update(struct reset_controller_dev *rcdev,
+                                unsigned long id, bool assert)
+{
+       unsigned int val;
+       struct atlantis_reset_controller *rst =
+               to_atlantis_reset_controller(rcdev);
+       const struct atlantis_reset_data *data = &rst->data->reset_data[id];
+       unsigned int mask = BIT(data->bit);
+       struct regmap *regmap = rst->regmap;
+
+       if (data->active_low ^ assert)
+               val = mask;
+       else
+               val = 0;
+
+       return regmap_update_bits(regmap, data->reg, mask, val);
+}
+
+static int atlantis_reset_assert(struct reset_controller_dev *rcdev,
+                                unsigned long id)
+{
+       return atlantis_reset_update(rcdev, id, true);
+}
+
+static int atlantis_reset_deassert(struct reset_controller_dev *rcdev,
+                                  unsigned long id)
+{
+       return atlantis_reset_update(rcdev, id, false);
+}
+
+static const struct reset_control_ops atlantis_reset_control_ops = {
+       .assert = atlantis_reset_assert,
+       .deassert = atlantis_reset_deassert,
+};
+
+static int
+atlantis_reset_controller_register(struct device *dev,
+                                  struct atlantis_reset_controller *controller)
+{
+       struct reset_controller_dev *rcdev = &controller->rcdev;
+
+       rcdev->ops = &atlantis_reset_control_ops;
+       rcdev->owner = THIS_MODULE;
+       rcdev->of_node = dev->of_node;
+       rcdev->nr_resets = controller->data->count;
+
+       return devm_reset_controller_register(dev, &controller->rcdev);
+}
+static int atlantis_reset_probe(struct auxiliary_device *adev,
+                               const struct auxiliary_device_id *id)
+{
+       struct atlantis_reset_controller *controller;
+       struct device *dev = &adev->dev;
+       struct regmap *regmap;
+
+       regmap = dev_get_regmap(dev->parent, NULL);
+       if (!regmap)
+               return -ENODEV;
+
+       controller = devm_kzalloc(dev, sizeof(*controller), GFP_KERNEL);
+       if (!controller)
+               return -ENOMEM;
+       controller->data =
+               (const struct atlantis_reset_controller_data *)id->driver_data;
+       controller->regmap = regmap;
+
+       return atlantis_reset_controller_register(dev, controller);
+}
+
+static const struct auxiliary_device_id atlantis_reset_ids[] = {
+       { .name = "atlantis_prcm.rcpu-reset",
+         .driver_data = (kernel_ulong_t)&atlantis_rcpu_reset_data },
+       {},
+};
+MODULE_DEVICE_TABLE(auxiliary, atlantis_reset_ids);
+
+static struct auxiliary_driver atlantis_reset_driver = {
+       .probe = atlantis_reset_probe,
+       .id_table = atlantis_reset_ids,
+};
+module_auxiliary_driver(atlantis_reset_driver);
+
+MODULE_AUTHOR("Anirudh Srinivasan <asrinivasan@oss.tenstorrent.com>");
+MODULE_DESCRIPTION("Atlantis PRCM reset controller driver");
+MODULE_LICENSE("GPL");