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