// SPDX-License-Identifier: GPL-2.0 /* * Tenstorrent Atlantis PRCM Reset Driver * * Copyright (c) 2026 Tenstorrent */ #include #include #include #include /* 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 "); MODULE_DESCRIPTION("Atlantis PRCM reset controller driver"); MODULE_LICENSE("GPL");