diff mbox series

[v4,13/21] riscv: Add Canaan Kendryte K210 reset controller

Message ID 20201202032500.206346-14-damien.lemoal@wdc.com (mailing list archive)
State New, archived
Headers show
Series RISC-V Kendryte K210 support improvements | expand

Commit Message

Damien Le Moal Dec. 2, 2020, 3:24 a.m. UTC
Add a reset controller driver for the Canaan Kendryte K210 SoC. This
driver relies on its syscon compatible parent node (sysctl) for its
register mapping. Automatically select this driver for compilation
when the SOC_CANAAN option is selected.

The MAINTAINERS file is updated, adding the entry "CANAAN/KENDRYTE K210
SOC RESET CONTROLLER DRIVER" with myself listed as maintainer for this
driver.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 MAINTAINERS                |   8 +++
 arch/riscv/Kconfig.socs    |   3 +
 drivers/reset/Kconfig      |   9 +++
 drivers/reset/Makefile     |   1 +
 drivers/reset/reset-k210.c | 141 +++++++++++++++++++++++++++++++++++++
 5 files changed, 162 insertions(+)
 create mode 100644 drivers/reset/reset-k210.c

Comments

Philipp Zabel Dec. 4, 2020, 10:49 a.m. UTC | #1
Hi Damien,

On Wed, 2020-12-02 at 12:24 +0900, Damien Le Moal wrote:
> Add a reset controller driver for the Canaan Kendryte K210 SoC. This
> driver relies on its syscon compatible parent node (sysctl) for its
> register mapping. Automatically select this driver for compilation
> when the SOC_CANAAN option is selected.
> 
> The MAINTAINERS file is updated, adding the entry "CANAAN/KENDRYTE K210
> SOC RESET CONTROLLER DRIVER" with myself listed as maintainer for this
> driver.
> 
> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
> ---
>  MAINTAINERS                |   8 +++
>  arch/riscv/Kconfig.socs    |   3 +
>  drivers/reset/Kconfig      |   9 +++
>  drivers/reset/Makefile     |   1 +
>  drivers/reset/reset-k210.c | 141 +++++++++++++++++++++++++++++++++++++
>  5 files changed, 162 insertions(+)
>  create mode 100644 drivers/reset/reset-k210.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a059ab02fa8a..c2b3d6e48cd5 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -3837,6 +3837,14 @@ L:	linux-gpio@vger.kernel.org (pinctrl driver)
>  F:	Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
>  F:	drivers/pinctrl/pinctrl-k210.c
>  
> +CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER
> +M:	Damien Le Moal <damien.lemoal@wdc.com>
> +L:	linux-kernel@vger.kernel.org
> +L:	linux-riscv@lists.infradead.org
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
> +F:	drivers/reset/reset-k210.c
> +
>  CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER
>  M:	Damien Le Moal <damien.lemoal@wdc.com>
>  L:	linux-riscv@lists.infradead.org
> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
> index 68bdd664b5c2..b3cd253ec2c2 100644
> --- a/arch/riscv/Kconfig.socs
> +++ b/arch/riscv/Kconfig.socs
> @@ -33,6 +33,9 @@ config SOC_CANAAN
>  	select CLK_K210
>  	select PINCTRL
>  	select PINCTRL_K210
> +	select ARCH_HAS_RESET_CONTROLLER
> +	select RESET_CONTROLLER
> +	select RESET_K210
>  	help
>  	  This enables support for Canaan Kendryte K210 SoC platform hardware.
>  
> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
> index 07d162b179fc..529d206cfdfd 100644
> --- a/drivers/reset/Kconfig
> +++ b/drivers/reset/Kconfig
> @@ -245,6 +245,15 @@ config RESET_ZYNQ
>  	help
>  	  This enables the reset controller driver for Xilinx Zynq SoCs.
>  
> +config RESET_K210
> +	bool "Reset controller driver for Canaan Kendryte K210 SoC"
> +	depends on RISCV && SOC_CANAAN
> +	depends on OF && MFD_SYSCON
> +	help
> +	  Support for the Canaan Kendryte K210 RISC-V SoC reset controller.
> +	  Say Y if you want to control reset signals provided by this
> +	  controller.
> +
>  source "drivers/reset/sti/Kconfig"
>  source "drivers/reset/hisilicon/Kconfig"
>  source "drivers/reset/tegra/Kconfig"
> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
> index 16947610cc3b..1730a31e6871 100644
> --- a/drivers/reset/Makefile
> +++ b/drivers/reset/Makefile
> @@ -33,4 +33,5 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
>  obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
>  obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
>  obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
> +obj-$(CONFIG_RESET_K210) += reset-k210.o
>  
> diff --git a/drivers/reset/reset-k210.c b/drivers/reset/reset-k210.c
> new file mode 100644
> index 000000000000..2cf9a63c763d
> --- /dev/null
> +++ b/drivers/reset/reset-k210.c
> @@ -0,0 +1,141 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2020 Western Digital Corporation or its affiliates.
> + */
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset-controller.h>
> +#include <linux/delay.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/regmap.h>
> +#include <soc/canaan/k210-sysctl.h>
> +
> +#include <dt-bindings/reset/k210-rst.h>
> +
> +#define K210_RST_MASK	0x27FFFFFF
> +
> +struct k210_rst {
> +	struct regmap *map;
> +	struct reset_controller_dev rcdev;
> +};
> +
> +static inline struct k210_rst *
> +to_k210_rst(struct reset_controller_dev *rcdev)
> +{
> +	return container_of(rcdev, struct k210_rst, rcdev);
> +}
> +
> +static inline int k210_rst_assert(struct reset_controller_dev *rcdev,
> +				  unsigned long id)
> +{
> +	struct k210_rst *ksr = to_k210_rst(rcdev);
> +	u32 bit = BIT(id);
> +
> +	if (!(bit & K210_RST_MASK))
> +		return -EINVAL;

Instead of checking this mask in the k210_rst_assert/deassert/status()
functions, you could implement a custom .of_xlate callback and disallow
requesting invalid resets in the first place.

regards
Philipp
Damien Le Moal Dec. 4, 2020, 11:16 a.m. UTC | #2
On 2020/12/04 19:49, Philipp Zabel wrote:
> Hi Damien,
> 
> On Wed, 2020-12-02 at 12:24 +0900, Damien Le Moal wrote:
>> Add a reset controller driver for the Canaan Kendryte K210 SoC. This
>> driver relies on its syscon compatible parent node (sysctl) for its
>> register mapping. Automatically select this driver for compilation
>> when the SOC_CANAAN option is selected.
>>
>> The MAINTAINERS file is updated, adding the entry "CANAAN/KENDRYTE K210
>> SOC RESET CONTROLLER DRIVER" with myself listed as maintainer for this
>> driver.
>>
>> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
>> ---
>>  MAINTAINERS                |   8 +++
>>  arch/riscv/Kconfig.socs    |   3 +
>>  drivers/reset/Kconfig      |   9 +++
>>  drivers/reset/Makefile     |   1 +
>>  drivers/reset/reset-k210.c | 141 +++++++++++++++++++++++++++++++++++++
>>  5 files changed, 162 insertions(+)
>>  create mode 100644 drivers/reset/reset-k210.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index a059ab02fa8a..c2b3d6e48cd5 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -3837,6 +3837,14 @@ L:	linux-gpio@vger.kernel.org (pinctrl driver)
>>  F:	Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
>>  F:	drivers/pinctrl/pinctrl-k210.c
>>  
>> +CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER
>> +M:	Damien Le Moal <damien.lemoal@wdc.com>
>> +L:	linux-kernel@vger.kernel.org
>> +L:	linux-riscv@lists.infradead.org
>> +S:	Maintained
>> +F:	Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
>> +F:	drivers/reset/reset-k210.c
>> +
>>  CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER
>>  M:	Damien Le Moal <damien.lemoal@wdc.com>
>>  L:	linux-riscv@lists.infradead.org
>> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
>> index 68bdd664b5c2..b3cd253ec2c2 100644
>> --- a/arch/riscv/Kconfig.socs
>> +++ b/arch/riscv/Kconfig.socs
>> @@ -33,6 +33,9 @@ config SOC_CANAAN
>>  	select CLK_K210
>>  	select PINCTRL
>>  	select PINCTRL_K210
>> +	select ARCH_HAS_RESET_CONTROLLER
>> +	select RESET_CONTROLLER
>> +	select RESET_K210
>>  	help
>>  	  This enables support for Canaan Kendryte K210 SoC platform hardware.
>>  
>> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
>> index 07d162b179fc..529d206cfdfd 100644
>> --- a/drivers/reset/Kconfig
>> +++ b/drivers/reset/Kconfig
>> @@ -245,6 +245,15 @@ config RESET_ZYNQ
>>  	help
>>  	  This enables the reset controller driver for Xilinx Zynq SoCs.
>>  
>> +config RESET_K210
>> +	bool "Reset controller driver for Canaan Kendryte K210 SoC"
>> +	depends on RISCV && SOC_CANAAN
>> +	depends on OF && MFD_SYSCON
>> +	help
>> +	  Support for the Canaan Kendryte K210 RISC-V SoC reset controller.
>> +	  Say Y if you want to control reset signals provided by this
>> +	  controller.
>> +
>>  source "drivers/reset/sti/Kconfig"
>>  source "drivers/reset/hisilicon/Kconfig"
>>  source "drivers/reset/tegra/Kconfig"
>> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
>> index 16947610cc3b..1730a31e6871 100644
>> --- a/drivers/reset/Makefile
>> +++ b/drivers/reset/Makefile
>> @@ -33,4 +33,5 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
>>  obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
>>  obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
>>  obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
>> +obj-$(CONFIG_RESET_K210) += reset-k210.o
>>  
>> diff --git a/drivers/reset/reset-k210.c b/drivers/reset/reset-k210.c
>> new file mode 100644
>> index 000000000000..2cf9a63c763d
>> --- /dev/null
>> +++ b/drivers/reset/reset-k210.c
>> @@ -0,0 +1,141 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * Copyright (c) 2020 Western Digital Corporation or its affiliates.
>> + */
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/reset-controller.h>
>> +#include <linux/delay.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/regmap.h>
>> +#include <soc/canaan/k210-sysctl.h>
>> +
>> +#include <dt-bindings/reset/k210-rst.h>
>> +
>> +#define K210_RST_MASK	0x27FFFFFF
>> +
>> +struct k210_rst {
>> +	struct regmap *map;
>> +	struct reset_controller_dev rcdev;
>> +};
>> +
>> +static inline struct k210_rst *
>> +to_k210_rst(struct reset_controller_dev *rcdev)
>> +{
>> +	return container_of(rcdev, struct k210_rst, rcdev);
>> +}
>> +
>> +static inline int k210_rst_assert(struct reset_controller_dev *rcdev,
>> +				  unsigned long id)
>> +{
>> +	struct k210_rst *ksr = to_k210_rst(rcdev);
>> +	u32 bit = BIT(id);
>> +
>> +	if (!(bit & K210_RST_MASK))
>> +		return -EINVAL;
> 
> Instead of checking this mask in the k210_rst_assert/deassert/status()
> functions, you could implement a custom .of_xlate callback and disallow
> requesting invalid resets in the first place.

OK. I did not know about this. Will look into it and send a v5.

Thanks !

> 
> regards
> Philipp
>
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index a059ab02fa8a..c2b3d6e48cd5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3837,6 +3837,14 @@  L:	linux-gpio@vger.kernel.org (pinctrl driver)
 F:	Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
 F:	drivers/pinctrl/pinctrl-k210.c
 
+CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER
+M:	Damien Le Moal <damien.lemoal@wdc.com>
+L:	linux-kernel@vger.kernel.org
+L:	linux-riscv@lists.infradead.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
+F:	drivers/reset/reset-k210.c
+
 CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER
 M:	Damien Le Moal <damien.lemoal@wdc.com>
 L:	linux-riscv@lists.infradead.org
diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index 68bdd664b5c2..b3cd253ec2c2 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -33,6 +33,9 @@  config SOC_CANAAN
 	select CLK_K210
 	select PINCTRL
 	select PINCTRL_K210
+	select ARCH_HAS_RESET_CONTROLLER
+	select RESET_CONTROLLER
+	select RESET_K210
 	help
 	  This enables support for Canaan Kendryte K210 SoC platform hardware.
 
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 07d162b179fc..529d206cfdfd 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -245,6 +245,15 @@  config RESET_ZYNQ
 	help
 	  This enables the reset controller driver for Xilinx Zynq SoCs.
 
+config RESET_K210
+	bool "Reset controller driver for Canaan Kendryte K210 SoC"
+	depends on RISCV && SOC_CANAAN
+	depends on OF && MFD_SYSCON
+	help
+	  Support for the Canaan Kendryte K210 RISC-V SoC reset controller.
+	  Say Y if you want to control reset signals provided by this
+	  controller.
+
 source "drivers/reset/sti/Kconfig"
 source "drivers/reset/hisilicon/Kconfig"
 source "drivers/reset/tegra/Kconfig"
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 16947610cc3b..1730a31e6871 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -33,4 +33,5 @@  obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
 obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
 obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
 obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
+obj-$(CONFIG_RESET_K210) += reset-k210.o
 
diff --git a/drivers/reset/reset-k210.c b/drivers/reset/reset-k210.c
new file mode 100644
index 000000000000..2cf9a63c763d
--- /dev/null
+++ b/drivers/reset/reset-k210.c
@@ -0,0 +1,141 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <soc/canaan/k210-sysctl.h>
+
+#include <dt-bindings/reset/k210-rst.h>
+
+#define K210_RST_MASK	0x27FFFFFF
+
+struct k210_rst {
+	struct regmap *map;
+	struct reset_controller_dev rcdev;
+};
+
+static inline struct k210_rst *
+to_k210_rst(struct reset_controller_dev *rcdev)
+{
+	return container_of(rcdev, struct k210_rst, rcdev);
+}
+
+static inline int k210_rst_assert(struct reset_controller_dev *rcdev,
+				  unsigned long id)
+{
+	struct k210_rst *ksr = to_k210_rst(rcdev);
+	u32 bit = BIT(id);
+
+	if (!(bit & K210_RST_MASK))
+		return -EINVAL;
+
+	dev_dbg(rcdev->dev, "assert %lu\n", id);
+
+	regmap_update_bits(ksr->map, K210_SYSCTL_PERI_RESET, bit, 1);
+
+	return 0;
+}
+
+static inline int k210_rst_deassert(struct reset_controller_dev *rcdev,
+				    unsigned long id)
+{
+	struct k210_rst *ksr = to_k210_rst(rcdev);
+	u32 bit = BIT(id);
+
+	if (!(bit & K210_RST_MASK))
+		return -EINVAL;
+
+	dev_dbg(rcdev->dev, "deassert %lu\n", id);
+
+	regmap_update_bits(ksr->map, K210_SYSCTL_PERI_RESET, bit, 0);
+
+	return 0;
+}
+
+static int k210_rst_reset(struct reset_controller_dev *rcdev,
+			  unsigned long id)
+{
+	int ret;
+
+	dev_dbg(rcdev->dev, "reset %lu\n", id);
+
+	ret = k210_rst_assert(rcdev, id);
+	if (ret == 0) {
+		udelay(10);
+		ret = k210_rst_deassert(rcdev, id);
+	}
+
+	return ret;
+}
+
+static int k210_rst_status(struct reset_controller_dev *rcdev,
+			   unsigned long id)
+{
+	struct k210_rst *ksr = to_k210_rst(rcdev);
+	u32 reg, bit = BIT(id);
+	int ret;
+
+	if (!(bit & K210_RST_MASK))
+		return -EINVAL;
+
+	ret = regmap_read(ksr->map, K210_SYSCTL_PERI_RESET, &reg);
+	if (ret)
+		return ret;
+
+	return ret & bit;
+}
+
+static const struct reset_control_ops k210_rst_ops = {
+	.assert		= k210_rst_assert,
+	.deassert	= k210_rst_deassert,
+	.reset		= k210_rst_reset,
+	.status		= k210_rst_status,
+};
+
+static int __init k210_rst_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct k210_rst *ksr;
+
+	dev_info(dev, "K210 reset controller\n");
+
+	if (!dev->parent) {
+		dev_err(&pdev->dev, "No parent for K210 reset controller\n");
+		return -ENODEV;
+	}
+
+	ksr = devm_kzalloc(dev, sizeof(*ksr), GFP_KERNEL);
+	if (!ksr)
+		return -ENOMEM;
+
+	ksr->map = syscon_node_to_regmap(dev->parent->of_node);
+	if (IS_ERR(ksr->map))
+		return PTR_ERR(ksr->map);
+
+	ksr->rcdev.owner = THIS_MODULE;
+	ksr->rcdev.dev = dev;
+	ksr->rcdev.of_node = dev->of_node;
+	ksr->rcdev.nr_resets = fls(K210_RST_MASK);
+	ksr->rcdev.ops = &k210_rst_ops;
+
+	return devm_reset_controller_register(dev, &ksr->rcdev);
+}
+
+static const struct of_device_id k210_rst_dt_ids[] = {
+	{ .compatible = "canaan,k210-rst" },
+};
+
+static struct platform_driver k210_rst_driver = {
+	.probe	= k210_rst_probe,
+	.driver = {
+		.name		= "k210-rst",
+		.of_match_table	= k210_rst_dt_ids,
+	},
+};
+builtin_platform_driver(k210_rst_driver);