Commit 4a653263 authored by Michal Wilczynski's avatar Michal Wilczynski Committed by Philipp Zabel
Browse files

reset: thead: Add TH1520 reset controller driver



Add reset controller driver for the T-HEAD TH1520 SoC that manages
hardware reset lines for various subsystems. The driver currently
implements support for GPU reset control, with infrastructure in place
to extend support for NPU and Watchdog Timer resets in future updates.

Reviewed-by: default avatarPhilipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: default avatarMichal Wilczynski <m.wilczynski@samsung.com>
Link: https://lore.kernel.org/r/20250303152511.494405-3-m.wilczynski@samsung.com


Signed-off-by: default avatarPhilipp Zabel <p.zabel@pengutronix.de>
parent 30e7573b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -20833,6 +20833,7 @@ F: drivers/mailbox/mailbox-th1520.c
F:	drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c
F:	drivers/pinctrl/pinctrl-th1520.c
F:	drivers/pmdomain/thead/
F:	drivers/reset/reset-th1520.c
F:	include/dt-bindings/clock/thead,th1520-clk-ap.h
F:	include/dt-bindings/power/thead,th1520-power.h
F:	include/dt-bindings/reset/thead,th1520-reset.h
+10 −0
Original line number Diff line number Diff line
@@ -279,6 +279,16 @@ config RESET_SUNXI
	help
	  This enables the reset driver for Allwinner SoCs.

config RESET_TH1520
	tristate "T-HEAD 1520 reset controller"
	depends on ARCH_THEAD || COMPILE_TEST
	select REGMAP_MMIO
	help
	  This driver provides support for the T-HEAD TH1520 SoC reset controller,
	  which manages hardware reset lines for SoC components such as the GPU.
	  Enable this option if you need to control hardware resets on TH1520-based
	  systems.

config RESET_TI_SCI
	tristate "TI System Control Interface (TI-SCI) reset driver"
	depends on TI_SCI_PROTOCOL || (COMPILE_TEST && TI_SCI_PROTOCOL=n)
+1 −0
Original line number Diff line number Diff line
@@ -36,6 +36,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_TH1520) += reset-th1520.o
obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o
obj-$(CONFIG_RESET_TI_TPS380X) += reset-tps380x.o
+135 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2024 Samsung Electronics Co., Ltd.
 * Author: Michal Wilczynski <m.wilczynski@samsung.com>
 */

#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/regmap.h>

#include <dt-bindings/reset/thead,th1520-reset.h>

 /* register offset in VOSYS_REGMAP */
#define TH1520_GPU_RST_CFG		0x0
#define TH1520_GPU_RST_CFG_MASK		GENMASK(1, 0)

/* register values */
#define TH1520_GPU_SW_GPU_RST		BIT(0)
#define TH1520_GPU_SW_CLKGEN_RST	BIT(1)

struct th1520_reset_priv {
	struct reset_controller_dev rcdev;
	struct regmap *map;
};

struct th1520_reset_map {
	u32 bit;
	u32 reg;
};

static const struct th1520_reset_map th1520_resets[] = {
	[TH1520_RESET_ID_GPU] = {
		.bit = TH1520_GPU_SW_GPU_RST,
		.reg = TH1520_GPU_RST_CFG,
	},
	[TH1520_RESET_ID_GPU_CLKGEN] = {
		.bit = TH1520_GPU_SW_CLKGEN_RST,
		.reg = TH1520_GPU_RST_CFG,
	}
};

static inline struct th1520_reset_priv *
to_th1520_reset(struct reset_controller_dev *rcdev)
{
	return container_of(rcdev, struct th1520_reset_priv, rcdev);
}

static int th1520_reset_assert(struct reset_controller_dev *rcdev,
			       unsigned long id)
{
	struct th1520_reset_priv *priv = to_th1520_reset(rcdev);
	const struct th1520_reset_map *reset;

	reset = &th1520_resets[id];

	return regmap_update_bits(priv->map, reset->reg, reset->bit, 0);
}

static int th1520_reset_deassert(struct reset_controller_dev *rcdev,
				 unsigned long id)
{
	struct th1520_reset_priv *priv = to_th1520_reset(rcdev);
	const struct th1520_reset_map *reset;

	reset = &th1520_resets[id];

	return regmap_update_bits(priv->map, reset->reg, reset->bit,
				  reset->bit);
}

static const struct reset_control_ops th1520_reset_ops = {
	.assert	= th1520_reset_assert,
	.deassert = th1520_reset_deassert,
};

static const struct regmap_config th1520_reset_regmap_config = {
	.reg_bits = 32,
	.val_bits = 32,
	.reg_stride = 4,
	.fast_io = true,
};

static int th1520_reset_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct th1520_reset_priv *priv;
	void __iomem *base;
	int ret;

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	base = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(base))
		return PTR_ERR(base);

	priv->map = devm_regmap_init_mmio(dev, base,
					  &th1520_reset_regmap_config);
	if (IS_ERR(priv->map))
		return PTR_ERR(priv->map);

	/* Initialize GPU resets to asserted state */
	ret = regmap_update_bits(priv->map, TH1520_GPU_RST_CFG,
				 TH1520_GPU_RST_CFG_MASK, 0);
	if (ret)
		return ret;

	priv->rcdev.owner = THIS_MODULE;
	priv->rcdev.nr_resets = ARRAY_SIZE(th1520_resets);
	priv->rcdev.ops = &th1520_reset_ops;
	priv->rcdev.of_node = dev->of_node;

	return devm_reset_controller_register(dev, &priv->rcdev);
}

static const struct of_device_id th1520_reset_match[] = {
	{ .compatible = "thead,th1520-reset" },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, th1520_reset_match);

static struct platform_driver th1520_reset_driver = {
	.driver = {
		.name = "th1520-reset",
		.of_match_table = th1520_reset_match,
	},
	.probe = th1520_reset_probe,
};
module_platform_driver(th1520_reset_driver);

MODULE_AUTHOR("Michal Wilczynski <m.wilczynski@samsung.com>");
MODULE_DESCRIPTION("T-HEAD TH1520 SoC reset controller");
MODULE_LICENSE("GPL");