1286763Smav// SPDX-License-Identifier: GPL-2.0+
2286763Smav/*
3286763Smav * Copyright (C) 2018 Xilinx, Inc.
4286763Smav *
5286763Smav */
6286763Smav
7286763Smav#include <linux/err.h>
8286763Smav#include <linux/of.h>
9286763Smav#include <linux/platform_device.h>
10286763Smav#include <linux/reset-controller.h>
11286763Smav#include <linux/firmware/xlnx-zynqmp.h>
12286763Smav
13286763Smav#define ZYNQMP_NR_RESETS (ZYNQMP_PM_RESET_END - ZYNQMP_PM_RESET_START)
14286763Smav#define ZYNQMP_RESET_ID ZYNQMP_PM_RESET_START
15286763Smav#define VERSAL_NR_RESETS	95
16321552Smav#define VERSAL_NET_NR_RESETS	176
17286763Smav
18286763Smavstruct zynqmp_reset_soc_data {
19286763Smav	u32 reset_id;
20286763Smav	u32 num_resets;
21286763Smav};
22286763Smav
23286763Smavstruct zynqmp_reset_data {
24286763Smav	struct reset_controller_dev rcdev;
25286763Smav	const struct zynqmp_reset_soc_data *data;
26321552Smav};
27321552Smav
28321552Smavstatic inline struct zynqmp_reset_data *
29321552Smavto_zynqmp_reset_data(struct reset_controller_dev *rcdev)
30321552Smav{
31321552Smav	return container_of(rcdev, struct zynqmp_reset_data, rcdev);
32286763Smav}
33286763Smav
34286763Smavstatic int zynqmp_reset_assert(struct reset_controller_dev *rcdev,
35286763Smav			       unsigned long id)
36286763Smav{
37286763Smav	struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
38286763Smav
39286763Smav	return zynqmp_pm_reset_assert(priv->data->reset_id + id,
40286763Smav				      PM_RESET_ACTION_ASSERT);
41286763Smav}
42286763Smav
43286763Smavstatic int zynqmp_reset_deassert(struct reset_controller_dev *rcdev,
44286763Smav				 unsigned long id)
45286763Smav{
46286763Smav	struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
47286763Smav
48286763Smav	return zynqmp_pm_reset_assert(priv->data->reset_id + id,
49286763Smav				      PM_RESET_ACTION_RELEASE);
50286763Smav}
51286763Smav
52286763Smavstatic int zynqmp_reset_status(struct reset_controller_dev *rcdev,
53286763Smav			       unsigned long id)
54286763Smav{
55286763Smav	struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
56286763Smav	int err;
57286763Smav	u32 val;
58286763Smav
59286763Smav	err = zynqmp_pm_reset_get_status(priv->data->reset_id + id, &val);
60286763Smav	if (err)
61286763Smav		return err;
62286763Smav
63286763Smav	return val;
64286763Smav}
65286763Smav
66286763Smavstatic int zynqmp_reset_reset(struct reset_controller_dev *rcdev,
67286763Smav			      unsigned long id)
68321553Smav{
69321553Smav	struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
70321552Smav
71286763Smav	return zynqmp_pm_reset_assert(priv->data->reset_id + id,
72286763Smav				      PM_RESET_ACTION_PULSE);
73286763Smav}
74286763Smav
75286763Smavstatic int zynqmp_reset_of_xlate(struct reset_controller_dev *rcdev,
76286763Smav				 const struct of_phandle_args *reset_spec)
77321553Smav{
78286763Smav	return reset_spec->args[0];
79286763Smav}
80286763Smav
81286763Smavstatic const struct zynqmp_reset_soc_data zynqmp_reset_data = {
82286763Smav	.reset_id = ZYNQMP_RESET_ID,
83286763Smav	.num_resets = ZYNQMP_NR_RESETS,
84286763Smav};
85286763Smav
86286763Smavstatic const struct zynqmp_reset_soc_data versal_reset_data = {
87286763Smav	.reset_id = 0,
88286763Smav	.num_resets = VERSAL_NR_RESETS,
89286763Smav};
90286763Smav
91286763Smavstatic const struct zynqmp_reset_soc_data versal_net_reset_data = {
92321553Smav	.reset_id = 0,
93286763Smav	.num_resets = VERSAL_NET_NR_RESETS,
94286763Smav};
95286763Smav
96321553Smavstatic const struct reset_control_ops zynqmp_reset_ops = {
97321552Smav	.reset = zynqmp_reset_reset,
98321552Smav	.assert = zynqmp_reset_assert,
99321552Smav	.deassert = zynqmp_reset_deassert,
100321553Smav	.status = zynqmp_reset_status,
101321553Smav};
102321552Smav
103321552Smavstatic int zynqmp_reset_probe(struct platform_device *pdev)
104321552Smav{
105321552Smav	struct zynqmp_reset_data *priv;
106321552Smav
107321552Smav	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
108321552Smav	if (!priv)
109321552Smav		return -ENOMEM;
110321552Smav
111321552Smav	priv->data = of_device_get_match_data(&pdev->dev);
112321553Smav	if (!priv->data)
113321552Smav		return -EINVAL;
114321552Smav
115321552Smav	priv->rcdev.ops = &zynqmp_reset_ops;
116286763Smav	priv->rcdev.owner = THIS_MODULE;
117286763Smav	priv->rcdev.of_node = pdev->dev.of_node;
118286763Smav	priv->rcdev.nr_resets = priv->data->num_resets;
119286763Smav	priv->rcdev.of_reset_n_cells = 1;
120286763Smav	priv->rcdev.of_xlate = zynqmp_reset_of_xlate;
121286763Smav
122286763Smav	return devm_reset_controller_register(&pdev->dev, &priv->rcdev);
123286763Smav}
124286763Smav
125286763Smavstatic const struct of_device_id zynqmp_reset_dt_ids[] = {
126286763Smav	{ .compatible = "xlnx,zynqmp-reset", .data = &zynqmp_reset_data, },
127286763Smav	{ .compatible = "xlnx,versal-reset", .data = &versal_reset_data, },
128286763Smav	{ .compatible = "xlnx,versal-net-reset", .data = &versal_net_reset_data, },
129286763Smav	{ /* sentinel */ },
130286763Smav};
131286763Smav
132286763Smavstatic struct platform_driver zynqmp_reset_driver = {
133286763Smav	.probe	= zynqmp_reset_probe,
134286763Smav	.driver = {
135286763Smav		.name		= KBUILD_MODNAME,
136286763Smav		.of_match_table	= zynqmp_reset_dt_ids,
137286763Smav	},
138321553Smav};
139286763Smav
140286763Smavstatic int __init zynqmp_reset_init(void)
141286763Smav{
142286763Smav	return platform_driver_register(&zynqmp_reset_driver);
143286763Smav}
144286763Smav
145286763Smavarch_initcall(zynqmp_reset_init);
146286763Smav