mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 23:09:29 +02:00
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>
174 lines
5.5 KiB
C
174 lines
5.5 KiB
C
// 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");
|