Skip to content

Commit 05f9e36

Browse files
ConchuODclaudiubeznea
authored andcommitted
reset: add polarfire soc reset support
Add support for the resets on Microchip's PolarFire SoC (MPFS). Reset control is a single register, wedged in between registers for clock control. To fit with existed DT etc, the reset controller is created using the aux device framework & set up in the clock driver. Reviewed-by: Philipp Zabel <[email protected]> Acked-by: Philipp Zabel <[email protected]> Reviewed-by: Daire McNamara <[email protected]> Signed-off-by: Conor Dooley <[email protected]> Reviewed-by: Claudiu Beznea <[email protected]> Signed-off-by: Claudiu Beznea <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent b56bae2 commit 05f9e36

File tree

3 files changed

+165
-1
lines changed

3 files changed

+165
-1
lines changed

drivers/reset/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,13 @@ config RESET_PISTACHIO
152152
help
153153
This enables the reset driver for ImgTec Pistachio SoCs.
154154

155+
config RESET_POLARFIRE_SOC
156+
bool "Microchip PolarFire SoC (MPFS) Reset Driver"
157+
depends on AUXILIARY_BUS && MCHP_CLK_MPFS
158+
default MCHP_CLK_MPFS
159+
help
160+
This driver supports peripheral reset for the Microchip PolarFire SoC
161+
155162
config RESET_QCOM_AOSS
156163
tristate "Qcom AOSS Reset Driver"
157164
depends on ARCH_QCOM || COMPILE_TEST

drivers/reset/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o
2222
obj-$(CONFIG_RESET_NPCM) += reset-npcm.o
2323
obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
2424
obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
25+
obj-$(CONFIG_RESET_POLARFIRE_SOC) += reset-mpfs.o
2526
obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o
2627
obj-$(CONFIG_RESET_QCOM_PDC) += reset-qcom-pdc.o
2728
obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o
@@ -40,4 +41,3 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
4041
obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
4142
obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
4243
obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
43-

drivers/reset/reset-mpfs.c

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* PolarFire SoC (MPFS) Peripheral Clock Reset Controller
4+
*
5+
* Author: Conor Dooley <[email protected]>
6+
* Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
7+
*
8+
*/
9+
#include <linux/auxiliary_bus.h>
10+
#include <linux/delay.h>
11+
#include <linux/module.h>
12+
#include <linux/platform_device.h>
13+
#include <linux/reset-controller.h>
14+
#include <dt-bindings/clock/microchip,mpfs-clock.h>
15+
#include <soc/microchip/mpfs.h>
16+
17+
/*
18+
* The ENVM reset is the lowest bit in the register & I am using the CLK_FOO
19+
* defines in the dt to make things easier to configure - so this is accounting
20+
* for the offset of 3 there.
21+
*/
22+
#define MPFS_PERIPH_OFFSET CLK_ENVM
23+
#define MPFS_NUM_RESETS 30u
24+
#define MPFS_SLEEP_MIN_US 100
25+
#define MPFS_SLEEP_MAX_US 200
26+
27+
/* block concurrent access to the soft reset register */
28+
static DEFINE_SPINLOCK(mpfs_reset_lock);
29+
30+
/*
31+
* Peripheral clock resets
32+
*/
33+
34+
static int mpfs_assert(struct reset_controller_dev *rcdev, unsigned long id)
35+
{
36+
unsigned long flags;
37+
u32 reg;
38+
39+
spin_lock_irqsave(&mpfs_reset_lock, flags);
40+
41+
reg = mpfs_reset_read(rcdev->dev);
42+
reg |= BIT(id);
43+
mpfs_reset_write(rcdev->dev, reg);
44+
45+
spin_unlock_irqrestore(&mpfs_reset_lock, flags);
46+
47+
return 0;
48+
}
49+
50+
static int mpfs_deassert(struct reset_controller_dev *rcdev, unsigned long id)
51+
{
52+
unsigned long flags;
53+
u32 reg;
54+
55+
spin_lock_irqsave(&mpfs_reset_lock, flags);
56+
57+
reg = mpfs_reset_read(rcdev->dev);
58+
reg &= ~BIT(id);
59+
mpfs_reset_write(rcdev->dev, reg);
60+
61+
spin_unlock_irqrestore(&mpfs_reset_lock, flags);
62+
63+
return 0;
64+
}
65+
66+
static int mpfs_status(struct reset_controller_dev *rcdev, unsigned long id)
67+
{
68+
u32 reg = mpfs_reset_read(rcdev->dev);
69+
70+
/*
71+
* It is safe to return here as MPFS_NUM_RESETS makes sure the sign bit
72+
* is never hit.
73+
*/
74+
return (reg & BIT(id));
75+
}
76+
77+
static int mpfs_reset(struct reset_controller_dev *rcdev, unsigned long id)
78+
{
79+
mpfs_assert(rcdev, id);
80+
81+
usleep_range(MPFS_SLEEP_MIN_US, MPFS_SLEEP_MAX_US);
82+
83+
mpfs_deassert(rcdev, id);
84+
85+
return 0;
86+
}
87+
88+
static const struct reset_control_ops mpfs_reset_ops = {
89+
.reset = mpfs_reset,
90+
.assert = mpfs_assert,
91+
.deassert = mpfs_deassert,
92+
.status = mpfs_status,
93+
};
94+
95+
static int mpfs_reset_xlate(struct reset_controller_dev *rcdev,
96+
const struct of_phandle_args *reset_spec)
97+
{
98+
unsigned int index = reset_spec->args[0];
99+
100+
/*
101+
* CLK_RESERVED does not map to a clock, but it does map to a reset,
102+
* so it has to be accounted for here. It is the reset for the fabric,
103+
* so if this reset gets called - do not reset it.
104+
*/
105+
if (index == CLK_RESERVED) {
106+
dev_err(rcdev->dev, "Resetting the fabric is not supported\n");
107+
return -EINVAL;
108+
}
109+
110+
if (index < MPFS_PERIPH_OFFSET || index >= (MPFS_PERIPH_OFFSET + rcdev->nr_resets)) {
111+
dev_err(rcdev->dev, "Invalid reset index %u\n", index);
112+
return -EINVAL;
113+
}
114+
115+
return index - MPFS_PERIPH_OFFSET;
116+
}
117+
118+
static int mpfs_reset_probe(struct auxiliary_device *adev,
119+
const struct auxiliary_device_id *id)
120+
{
121+
struct device *dev = &adev->dev;
122+
struct reset_controller_dev *rcdev;
123+
124+
rcdev = devm_kzalloc(dev, sizeof(*rcdev), GFP_KERNEL);
125+
if (!rcdev)
126+
return -ENOMEM;
127+
128+
rcdev->dev = dev;
129+
rcdev->dev->parent = dev->parent;
130+
rcdev->ops = &mpfs_reset_ops;
131+
rcdev->of_node = dev->parent->of_node;
132+
rcdev->of_reset_n_cells = 1;
133+
rcdev->of_xlate = mpfs_reset_xlate;
134+
rcdev->nr_resets = MPFS_NUM_RESETS;
135+
136+
return devm_reset_controller_register(dev, rcdev);
137+
}
138+
139+
static const struct auxiliary_device_id mpfs_reset_ids[] = {
140+
{
141+
.name = "clk_mpfs.reset-mpfs",
142+
},
143+
{ }
144+
};
145+
MODULE_DEVICE_TABLE(auxiliary, mpfs_reset_ids);
146+
147+
static struct auxiliary_driver mpfs_reset_driver = {
148+
.probe = mpfs_reset_probe,
149+
.id_table = mpfs_reset_ids,
150+
};
151+
152+
module_auxiliary_driver(mpfs_reset_driver);
153+
154+
MODULE_DESCRIPTION("Microchip PolarFire SoC Reset Driver");
155+
MODULE_AUTHOR("Conor Dooley <[email protected]>");
156+
MODULE_LICENSE("GPL");
157+
MODULE_IMPORT_NS(MCHP_CLK_MPFS);

0 commit comments

Comments
 (0)