Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux 6.6 th1520 reset driver #31

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
- Hengqiang Ming <[email protected]>

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 <dt-bindings/reset/thead,th1520-reset.h>

soc {
#address-cells = <2>;
#size-cells = <2>;

reset-controller@ffef014000 {
compatible = "thead,th1520-reset", "syscon";
reg = <0xff 0xef014000 0x0 0x1000>;
#reset-cells = <1>;
};
};
15 changes: 15 additions & 0 deletions arch/riscv/boot/dts/thead/th1520.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <dt-bindings/clock/th1520-dspsys.h>
#include <dt-bindings/clock/th1520-audiosys.h>
#include <dt-bindings/clock/th1520-miscsys.h>
#include <dt-bindings/reset/thead,th1520-reset.h>

/ {
compatible = "thead,th1520";
Expand Down Expand Up @@ -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";
};
};
};
10 changes: 10 additions & 0 deletions drivers/reset/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions drivers/reset/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
140 changes: 140 additions & 0 deletions drivers/reset/reset-th1520.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// SPDX-License-Identifier: GPL-2.0-only

#include <linux/mfd/syscon.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/regmap.h>
#include <dt-bindings/reset/thead,th1520-reset.h>

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 <[email protected]>");
MODULE_DESCRIPTION("Thead th1520 reset driver");
MODULE_LICENSE("GPL v2");
13 changes: 13 additions & 0 deletions include/dt-bindings/reset/thead,th1520-reset.h
Original file line number Diff line number Diff line change
@@ -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
Loading