xref: /linux/drivers/reset/starfive/reset-starfive-jh71x0.c (revision c16e5c94c8c2f0c20f5ce594188f84fd00040378)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Reset driver for the StarFive JH71X0 SoCs
4  *
5  * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk>
6  */
7 
8 #include <linux/bitmap.h>
9 #include <linux/device.h>
10 #include <linux/io.h>
11 #include <linux/iopoll.h>
12 #include <linux/reset-controller.h>
13 #include <linux/spinlock.h>
14 
15 #include "reset-starfive-jh71x0.h"
16 
17 struct jh71x0_reset {
18 	struct reset_controller_dev rcdev;
19 	/* protect registers against concurrent read-modify-write */
20 	spinlock_t lock;
21 	void __iomem *assert;
22 	void __iomem *status;
23 	const u32 *asserted;
24 };
25 
26 static inline struct jh71x0_reset *
jh71x0_reset_from(struct reset_controller_dev * rcdev)27 jh71x0_reset_from(struct reset_controller_dev *rcdev)
28 {
29 	return container_of(rcdev, struct jh71x0_reset, rcdev);
30 }
31 
jh71x0_reset_update(struct reset_controller_dev * rcdev,unsigned long id,bool assert)32 static int jh71x0_reset_update(struct reset_controller_dev *rcdev,
33 			       unsigned long id, bool assert)
34 {
35 	struct jh71x0_reset *data = jh71x0_reset_from(rcdev);
36 	unsigned long offset = id / 32;
37 	u32 mask = BIT(id % 32);
38 	void __iomem *reg_assert = data->assert + offset * sizeof(u32);
39 	void __iomem *reg_status = data->status + offset * sizeof(u32);
40 	u32 done = data->asserted ? data->asserted[offset] & mask : 0;
41 	u32 value;
42 	unsigned long flags;
43 	int ret;
44 
45 	if (!assert)
46 		done ^= mask;
47 
48 	spin_lock_irqsave(&data->lock, flags);
49 
50 	value = readl(reg_assert);
51 	if (assert)
52 		value |= mask;
53 	else
54 		value &= ~mask;
55 	writel(value, reg_assert);
56 
57 	/* if the associated clock is gated, deasserting might otherwise hang forever */
58 	ret = readl_poll_timeout_atomic(reg_status, value, (value & mask) == done, 0, 1000);
59 
60 	spin_unlock_irqrestore(&data->lock, flags);
61 	return ret;
62 }
63 
jh71x0_reset_assert(struct reset_controller_dev * rcdev,unsigned long id)64 static int jh71x0_reset_assert(struct reset_controller_dev *rcdev,
65 			       unsigned long id)
66 {
67 	return jh71x0_reset_update(rcdev, id, true);
68 }
69 
jh71x0_reset_deassert(struct reset_controller_dev * rcdev,unsigned long id)70 static int jh71x0_reset_deassert(struct reset_controller_dev *rcdev,
71 				 unsigned long id)
72 {
73 	return jh71x0_reset_update(rcdev, id, false);
74 }
75 
jh71x0_reset_reset(struct reset_controller_dev * rcdev,unsigned long id)76 static int jh71x0_reset_reset(struct reset_controller_dev *rcdev,
77 			      unsigned long id)
78 {
79 	int ret;
80 
81 	ret = jh71x0_reset_assert(rcdev, id);
82 	if (ret)
83 		return ret;
84 
85 	return jh71x0_reset_deassert(rcdev, id);
86 }
87 
jh71x0_reset_status(struct reset_controller_dev * rcdev,unsigned long id)88 static int jh71x0_reset_status(struct reset_controller_dev *rcdev,
89 			       unsigned long id)
90 {
91 	struct jh71x0_reset *data = jh71x0_reset_from(rcdev);
92 	unsigned long offset = id / 32;
93 	u32 mask = BIT(id % 32);
94 	void __iomem *reg_status = data->status + offset * sizeof(u32);
95 	u32 value = readl(reg_status);
96 
97 	if (!data->asserted)
98 		return !(value & mask);
99 
100 	return !((value ^ data->asserted[offset]) & mask);
101 }
102 
103 static const struct reset_control_ops jh71x0_reset_ops = {
104 	.assert		= jh71x0_reset_assert,
105 	.deassert	= jh71x0_reset_deassert,
106 	.reset		= jh71x0_reset_reset,
107 	.status		= jh71x0_reset_status,
108 };
109 
reset_starfive_jh71x0_register(struct device * dev,struct device_node * of_node,void __iomem * assert,void __iomem * status,const u32 * asserted,unsigned int nr_resets,struct module * owner)110 int reset_starfive_jh71x0_register(struct device *dev, struct device_node *of_node,
111 				   void __iomem *assert, void __iomem *status,
112 				   const u32 *asserted, unsigned int nr_resets,
113 				   struct module *owner)
114 {
115 	struct jh71x0_reset *data;
116 
117 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
118 	if (!data)
119 		return -ENOMEM;
120 
121 	data->rcdev.ops = &jh71x0_reset_ops;
122 	data->rcdev.owner = owner;
123 	data->rcdev.nr_resets = nr_resets;
124 	data->rcdev.dev = dev;
125 	data->rcdev.of_node = of_node;
126 
127 	spin_lock_init(&data->lock);
128 	data->assert = assert;
129 	data->status = status;
130 	data->asserted = asserted;
131 
132 	return devm_reset_controller_register(dev, &data->rcdev);
133 }
134 EXPORT_SYMBOL_GPL(reset_starfive_jh71x0_register);
135