diff --git a/Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml b/Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml new file mode 100644 index 0000000000000..b868c174b4fa7 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/reset/thead,th1520-reset.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: T-HEAD th1520 SoC Reset Controller + +maintainers: + - Kwanghoon Son + - Hengqiang Ming + +properties: + compatible: + items: + - const: thead,th1520-reset + - const: syscon + + reg: + maxItems: 1 + + '#reset-cells': + const: 1 + +required: + - compatible + - reg + - '#reset-cells' + +additionalProperties: false + +examples: + - | + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + reset-controller@ffef014000 { + compatible = "thead,th1520-reset", "syscon"; + reg = <0xff 0xef014000 0x0 0x1000>; + #reset-cells = <1>; + }; + }; diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index c8e425de61439..4496c51053d46 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -12,6 +12,7 @@ #include #include #include +#include / { compatible = "thead,th1520"; @@ -852,5 +853,19 @@ #clock-cells = <1>; status = "okay"; }; + + rst: reset-controller@ffef014000 { + compatible = "thead,th1520-reset", "syscon"; + reg = <0xff 0xef014000 0x0 0x1000>; + #reset-cells = <1>; + status = "okay"; + }; + + vpsys_rst: vpsys-reset-controller@ffecc30000 { + compatible = "thead,th1520-vpsys-reset","syscon"; + reg = <0xff 0xecc30000 0x0 0x1000>; + #reset-cells = <1>; + status = "okay"; + }; }; }; diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index ccd59ddd76100..ec69e6bbba6e5 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -253,6 +253,16 @@ config RESET_SUNXI help This enables the reset driver for Allwinner SoCs. +config RESET_TH1520 + bool "TH1520 Reset Driver" + depends on (ARCH_THEAD || COMPILE_TEST) && OF + select MFD_SYSCON + default ARCH_THEAD + help + Support for the T-HEAD 1520 RISC-V SoC reset controller. + Say Y if you want to control reset signals provided by this + controller. + config RESET_TI_SCI tristate "TI System Control Interface (TI-SCI) reset driver" depends on TI_SCI_PROTOCOL || (COMPILE_TEST && TI_SCI_PROTOCOL=n) diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 8270da8a4baa6..5c858e62241a9 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -33,6 +33,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 diff --git a/drivers/reset/reset-th1520.c b/drivers/reset/reset-th1520.c new file mode 100644 index 0000000000000..fb9e74ff4c83b --- /dev/null +++ b/drivers/reset/reset-th1520.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include + +struct th1520_rst_signal { + unsigned int offset, bit; +}; + +struct th1520_rst_variant { + const struct th1520_rst_signal *signals; + unsigned int signals_num; +}; + +struct th1520_rst { + struct reset_controller_dev rcdev; + struct regmap *regmap; + const struct th1520_rst_signal *signals; +}; + +enum th1520_rst_registers { + RST_WDT0 = 0x0034, + RST_WDT1 = 0x0038, + RST_NPU = 0x01b0, +}; + +enum th1520_vpsys_rst_registers { + RST_FCE = 0x0004, +}; + +static int th1520_reset_update(struct th1520_rst *rst, unsigned long id, + unsigned int value) +{ + const struct th1520_rst_signal *signal = &rst->signals[id]; + + return regmap_update_bits(rst->regmap, signal->offset, signal->bit, + value); +} + +static const struct th1520_rst_signal th1520_rst_signals[] = { + [TH1520_RESET_WDT0] = { RST_WDT0, BIT(0) }, + [TH1520_RESET_WDT1] = { RST_WDT1, BIT(0) }, + [TH1520_RESET_NPU] = { RST_NPU, BIT(0) }, +}; + +static const struct th1520_rst_signal th1520_vpsys_rst_signals[] = { + [TH1520_RESET_FCE] = { RST_FCE, BIT(0)|BIT(1)|BIT(4)|BIT(5) }, +}; + +static struct th1520_rst *to_th1520_rst(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct th1520_rst, rcdev); +} + +static int th1520_reset_set(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct th1520_rst *rst = to_th1520_rst(rcdev); + const unsigned int bit = rst->signals[id].bit; + unsigned int value = assert ? bit : 0; + + return th1520_reset_update(rst, id, value); +} + +static int th1520_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return th1520_reset_set(rcdev, id, false); +} + +static int th1520_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return th1520_reset_set(rcdev, id, true); +} + +static const struct reset_control_ops th1520_rst_ops = { + .assert = th1520_reset_assert, + .deassert = th1520_reset_deassert, +}; + +static const struct th1520_rst_variant variant_th1520 = { + .signals = th1520_rst_signals, + .signals_num = ARRAY_SIZE(th1520_rst_signals), +}; + +static const struct th1520_rst_variant variant_th1520_vpsys = { + .signals = th1520_vpsys_rst_signals, + .signals_num = ARRAY_SIZE(th1520_vpsys_rst_signals), +}; + +static int th1520_reset_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct th1520_rst *rst; + struct regmap_config config = { .name = "rst" }; + const struct th1520_rst_variant *variant = of_device_get_match_data(dev); + + rst = devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL); + if (!rst) + return -ENOMEM; + + rst->signals = variant->signals; + rst->regmap = syscon_node_to_regmap(dev->of_node); + if (IS_ERR(rst->regmap)) + return PTR_ERR(rst->regmap); + + regmap_attach_dev(dev, rst->regmap, &config); + + rst->rcdev.owner = THIS_MODULE; + rst->rcdev.dev = dev; + rst->rcdev.of_node = dev->of_node; + rst->rcdev.ops = &th1520_rst_ops; + rst->rcdev.nr_resets = variant->signals_num; + + return devm_reset_controller_register(dev, &rst->rcdev); +} + +static const struct of_device_id th1520_reset_dt_ids[] = { + { .compatible = "thead,th1520-reset", .data = &variant_th1520 }, + { .compatible = "thead,th1520-vpsys-reset", .data = &variant_th1520_vpsys }, + { /* sentinel */ }, +}; + +static struct platform_driver th1520_reset_driver = { + .probe = th1520_reset_probe, + .driver = { + .name = "th1520-reset", + .of_match_table = th1520_reset_dt_ids, + }, +}; +builtin_platform_driver(th1520_reset_driver); + +MODULE_AUTHOR("zenglinghui.zlh "); +MODULE_DESCRIPTION("Thead th1520 reset driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/dt-bindings/reset/thead,th1520-reset.h b/include/dt-bindings/reset/thead,th1520-reset.h new file mode 100644 index 0000000000000..19476bf389829 --- /dev/null +++ b/include/dt-bindings/reset/thead,th1520-reset.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ + +#ifndef DT_BINDING_RESET_TH1520_H +#define DT_BINDING_RESET_TH1520_H + +#define TH1520_RESET_WDT0 0 +#define TH1520_RESET_WDT1 1 +#define TH1520_RESET_NPU 2 + +// vpsys reset +#define TH1520_RESET_FCE 100 + +#endif