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