Skip to content

Commit 1f99d0f

Browse files
committed
Support audio reset in reset controller driver for Starfive JH7100 SOC
Signed-off-by: Walker Chen <walker.chen@starfivetech.com>
1 parent c4160ef commit 1f99d0f

File tree

4 files changed

+203
-69
lines changed

4 files changed

+203
-69
lines changed

arch/riscv/boot/dts/starfive/jh7100.dtsi

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,11 +295,17 @@
295295
};
296296

297297
rstgen: reset-controller@11840000 {
298-
compatible = "starfive,jh7100-reset";
298+
compatible = "starfive,jh7100-reset", "syscon";
299299
reg = <0x0 0x11840000 0x0 0x10000>;
300300
#reset-cells = <1>;
301301
};
302302

303+
audrst: reset-controller@10490000 {
304+
compatible = "starfive,jh7100-reset-audio", "syscon";
305+
reg = <0x0 0x10490000 0x0 0x10000>;
306+
#reset-cells = <1>;
307+
};
308+
303309
qspi: spi@11860000 {
304310
compatible = "cdns,qspi-nor";
305311
reg = <0x0 0x11860000 0x0 0x10000>,

drivers/reset/reset-starfive-jh7100.c

Lines changed: 136 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
* Reset driver for the StarFive JH7100 SoC
44
*
55
* Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk>
6+
* Copyright (C) 2021 Walker Chen <walker.chen@starfivetech.com>
67
*/
78

89
#include <linux/bitmap.h>
910
#include <linux/io.h>
10-
#include <linux/iopoll.h>
11-
#include <linux/mod_devicetable.h>
11+
#include <linux/of_device.h>
12+
#include <linux/regmap.h>
13+
#include <linux/mfd/syscon.h>
1214
#include <linux/platform_device.h>
1315
#include <linux/reset-controller.h>
1416
#include <linux/spinlock.h>
@@ -25,36 +27,30 @@
2527
#define JH7100_RESET_STATUS2 0x18
2628
#define JH7100_RESET_STATUS3 0x1c
2729

28-
#if BITS_PER_LONG == 64
29-
#define jh7100_reset_read readq
30-
#define jh7100_reset_write writeq
31-
#else
32-
#define jh7100_reset_read readl
33-
#define jh7100_reset_write writel
34-
#endif
30+
#define JH7100_AUDIO_RESET_STATUS0 0x4
3531

36-
/*
37-
* Writing a 1 to the n'th bit of the m'th ASSERT register asserts
38-
* line 32m + n, and writing a 0 deasserts the same line.
39-
* Most reset lines have their status inverted so a 0 bit in the STATUS
40-
* register means the line is asserted and a 1 means it's deasserted. A few
41-
* lines don't though, so store the expected value of the status registers when
42-
* all lines are asserted.
43-
*/
44-
static const DECLARE_BITMAP(jh7100_reset_asserted, 4 * 32) = {
45-
BITMAP_FROM_U64(BIT_ULL_MASK(JH7100_RST_U74) |
46-
BIT_ULL_MASK(JH7100_RST_VP6_DRESET) |
47-
BIT_ULL_MASK(JH7100_RST_VP6_BRESET) |
48-
BIT_ULL_MASK(JH7100_RST_HIFI4_DRESET) |
49-
BIT_ULL_MASK(JH7100_RST_HIFI4_BRESET)),
50-
BITMAP_FROM_U64(BIT_ULL_MASK(JH7100_RST_E24)),
32+
enum jh7100_reset_ctrl_type {
33+
PERIPHERAL = 0,
34+
AUDIO,
35+
ISP,
36+
};
37+
38+
static const u32 jh7100_reset_asserted[4] = {
39+
BIT(JH7100_RST_U74 % 32) |
40+
BIT(JH7100_RST_VP6_DRESET % 32) |
41+
BIT(JH7100_RST_VP6_BRESET % 32),
42+
43+
BIT(JH7100_RST_HIFI4_DRESET % 32) |
44+
BIT(JH7100_RST_HIFI4_BRESET % 32),
45+
46+
BIT_MASK(JH7100_RST_E24 % 32)
5147
};
5248

5349
struct jh7100_reset {
5450
struct reset_controller_dev rcdev;
5551
/* protect registers against concurrent read-modify-write */
5652
spinlock_t lock;
57-
void __iomem *base;
53+
struct regmap *regmap;
5854
};
5955

6056
static inline struct jh7100_reset *
@@ -63,106 +59,178 @@ jh7100_reset_from(struct reset_controller_dev *rcdev)
6359
return container_of(rcdev, struct jh7100_reset, rcdev);
6460
}
6561

66-
static int jh7100_reset_update(struct reset_controller_dev *rcdev,
67-
unsigned long id, bool assert)
62+
static int jh7100_reset_update(struct reset_controller_dev *rcdev, unsigned long id,
63+
unsigned int reg_status, bool assert)
6864
{
6965
struct jh7100_reset *data = jh7100_reset_from(rcdev);
70-
unsigned long offset = id / BITS_PER_LONG;
71-
void __iomem *reg_assert = data->base + JH7100_RESET_ASSERT0 + offset * sizeof(long);
72-
void __iomem *reg_status = data->base + JH7100_RESET_STATUS0 + offset * sizeof(long);
73-
unsigned long mask = BIT_MASK(id);
74-
unsigned long done = jh7100_reset_asserted[offset] & mask;
75-
unsigned long value;
66+
unsigned long bank = id / 32;
67+
u32 offset = JH7100_RESET_ASSERT0 + 4 * bank;
68+
u32 status = reg_status + 4 * bank;
69+
u32 mask = BIT(id % 32);
70+
u32 done = jh7100_reset_asserted[bank] & mask;
7671
unsigned long flags;
77-
int ret;
72+
unsigned long timeout;
73+
u32 value = 0;
74+
int ret = 0;
7875

7976
if (!assert)
8077
done ^= mask;
8178

8279
spin_lock_irqsave(&data->lock, flags);
8380

84-
value = jh7100_reset_read(reg_assert);
81+
regmap_read(data->regmap, offset, &value);
8582
if (assert)
8683
value |= mask;
8784
else
8885
value &= ~mask;
89-
jh7100_reset_write(value, reg_assert);
86+
regmap_write(data->regmap, offset, value);
9087

91-
/* if the associated clock is gated, deasserting might otherwise hang forever */
92-
ret = readx_poll_timeout_atomic(jh7100_reset_read, reg_status, value,
93-
(value & mask) == done, 0, 1000);
88+
timeout = jiffies + msecs_to_jiffies(10);
89+
do {
90+
regmap_read(data->regmap, status, &value);
91+
if (time_after(jiffies, timeout)) {
92+
ret = -ETIMEDOUT;
93+
break;
94+
}
95+
} while ((value & mask) != done);
9496

9597
spin_unlock_irqrestore(&data->lock, flags);
9698
return ret;
9799
}
98100

99-
static int jh7100_reset_assert(struct reset_controller_dev *rcdev,
101+
static int jh7100_periph_reset_assert(struct reset_controller_dev *rcdev,
100102
unsigned long id)
101103
{
102-
return jh7100_reset_update(rcdev, id, true);
104+
return jh7100_reset_update(rcdev, id, JH7100_RESET_STATUS0, true);
103105
}
104106

105-
static int jh7100_reset_deassert(struct reset_controller_dev *rcdev,
107+
static int jh7100_periph_reset_deassert(struct reset_controller_dev *rcdev,
106108
unsigned long id)
107109
{
108-
return jh7100_reset_update(rcdev, id, false);
110+
return jh7100_reset_update(rcdev, id, JH7100_RESET_STATUS0, false);
109111
}
110112

111-
static int jh7100_reset_reset(struct reset_controller_dev *rcdev,
113+
static int jh7100_periph_reset_reset(struct reset_controller_dev *rcdev,
112114
unsigned long id)
113115
{
114-
int ret;
115-
116-
ret = jh7100_reset_assert(rcdev, id);
116+
int ret = jh7100_periph_reset_assert(rcdev, id);
117117
if (ret)
118118
return ret;
119119

120-
return jh7100_reset_deassert(rcdev, id);
120+
return jh7100_periph_reset_deassert(rcdev, id);
121121
}
122122

123-
static int jh7100_reset_status(struct reset_controller_dev *rcdev,
124-
unsigned long id)
123+
static int jh7100_get_reset_status(struct reset_controller_dev *rcdev,
124+
unsigned int reg_status,
125+
unsigned long id)
125126
{
126127
struct jh7100_reset *data = jh7100_reset_from(rcdev);
127-
unsigned long offset = id / BITS_PER_LONG;
128-
void __iomem *reg_status = data->base + JH7100_RESET_STATUS0 + offset * sizeof(long);
129-
unsigned long value = jh7100_reset_read(reg_status);
130-
unsigned long mask = BIT_MASK(id);
128+
unsigned long bank = id / 32;
129+
unsigned long mask = BIT(id % 32);
130+
u32 value = 0;
131+
132+
reg_status = reg_status + 4 * bank;
133+
regmap_read(data->regmap, reg_status, &value);
131134

132-
return !((value ^ jh7100_reset_asserted[offset]) & mask);
135+
return !((value ^ jh7100_reset_asserted[bank]) & mask);
133136
}
134137

135-
static const struct reset_control_ops jh7100_reset_ops = {
136-
.assert = jh7100_reset_assert,
137-
.deassert = jh7100_reset_deassert,
138-
.reset = jh7100_reset_reset,
139-
.status = jh7100_reset_status,
138+
static int jh7100_periph_reset_status(struct reset_controller_dev *rcdev,
139+
unsigned long id)
140+
{
141+
return jh7100_get_reset_status(rcdev, JH7100_RESET_STATUS0, id);
142+
}
143+
144+
static const struct reset_control_ops jh7100_periph_reset_ops = {
145+
.assert = jh7100_periph_reset_assert,
146+
.deassert = jh7100_periph_reset_deassert,
147+
.reset = jh7100_periph_reset_reset,
148+
.status = jh7100_periph_reset_status,
149+
};
150+
151+
static int jh7100_audio_reset_assert(struct reset_controller_dev *rcdev,
152+
unsigned long id)
153+
{
154+
return jh7100_reset_update(rcdev, id, JH7100_AUDIO_RESET_STATUS0, true);
155+
}
156+
157+
static int jh7100_audio_reset_deassert(struct reset_controller_dev *rcdev,
158+
unsigned long id)
159+
{
160+
return jh7100_reset_update(rcdev, id, JH7100_AUDIO_RESET_STATUS0, false);
161+
}
162+
163+
static int jh7100_audio_reset_reset(struct reset_controller_dev *rcdev,
164+
unsigned long id)
165+
{
166+
int ret = jh7100_audio_reset_assert(rcdev, id);
167+
if (ret)
168+
return ret;
169+
170+
return jh7100_audio_reset_deassert(rcdev, id);
171+
}
172+
173+
static int jh7100_audio_reset_status(struct reset_controller_dev *rcdev,
174+
unsigned long id)
175+
{
176+
return jh7100_get_reset_status(rcdev, JH7100_AUDIO_RESET_STATUS0, id);
177+
}
178+
179+
static const struct reset_control_ops jh7100_audio_reset_ops = {
180+
.assert = jh7100_audio_reset_assert,
181+
.deassert = jh7100_audio_reset_deassert,
182+
.reset = jh7100_audio_reset_reset,
183+
.status = jh7100_audio_reset_status,
140184
};
141185

142186
static int __init jh7100_reset_probe(struct platform_device *pdev)
143187
{
188+
enum jh7100_reset_ctrl_type type;
189+
struct regmap *regmap;
190+
struct device_node *np = pdev->dev.of_node;
191+
struct device *dev = &pdev->dev;
144192
struct jh7100_reset *data;
145193

146194
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
147195
if (!data)
148196
return -ENOMEM;
149197

150-
data->base = devm_platform_ioremap_resource(pdev, 0);
151-
if (IS_ERR(data->base))
152-
return PTR_ERR(data->base);
198+
type = (enum jh7100_reset_ctrl_type)of_device_get_match_data(dev);
153199

154-
data->rcdev.ops = &jh7100_reset_ops;
200+
regmap = syscon_node_to_regmap(np);
201+
if (IS_ERR(regmap)) {
202+
dev_err(dev, "failed to get reset controller regmap\n");
203+
return PTR_ERR(regmap);
204+
}
205+
206+
data->regmap = regmap;
207+
data->rcdev.of_node = np;
208+
data->rcdev.dev = dev;
155209
data->rcdev.owner = THIS_MODULE;
156-
data->rcdev.nr_resets = JH7100_RSTN_END;
157-
data->rcdev.dev = &pdev->dev;
158-
data->rcdev.of_node = pdev->dev.of_node;
210+
if (type == PERIPHERAL) {
211+
data->rcdev.ops = &jh7100_periph_reset_ops;
212+
data->rcdev.nr_resets = JH7100_RSTN_END;
213+
} else if (type == AUDIO) {
214+
data->rcdev.ops = &jh7100_audio_reset_ops;
215+
data->rcdev.nr_resets = JH7100_AUDIO_RSTN_END;
216+
} else {
217+
;
218+
}
219+
159220
spin_lock_init(&data->lock);
160221

161222
return devm_reset_controller_register(&pdev->dev, &data->rcdev);
162223
}
163224

164225
static const struct of_device_id jh7100_reset_dt_ids[] = {
165-
{ .compatible = "starfive,jh7100-reset" },
226+
{
227+
.compatible = "starfive,jh7100-reset",
228+
.data = (void *)PERIPHERAL,
229+
},
230+
{
231+
.compatible = "starfive,jh7100-reset-audio",
232+
.data = (void *)AUDIO,
233+
},
166234
{ /* sentinel */ }
167235
};
168236

include/dt-bindings/clock/starfive-jh7100.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,4 +199,41 @@
199199

200200
#define JH7100_CLK_END 189
201201

202+
/* audio */
203+
#define JH7100_CLK_ADC_MCLK 0
204+
#define JH7100_CLK_I2S1_MCLK 1
205+
#define JH7100_CLK_APB_I2SADC 2
206+
#define JH7100_CLK_I2SADC_BCLK 3
207+
#define JH7100_CLK_I2SADC_BCLK_INV 4
208+
#define JH7100_CLK_I2SADC_LRCLK 5
209+
#define JH7100_CLK_APB_PDM 6
210+
#define JH7100_CLK_PDM_MCLK 7
211+
#define JH7100_CLK_APB_I2SVAD 8
212+
#define JH7100_CLK_SPDIF 9
213+
#define JH7100_CLK_APB_SPDIF 10
214+
#define JH7100_CLK_APB_PWMDAC 11
215+
#define JH7100_CLK_DAC_MCLK 12
216+
#define JH7100_CLK_APB_I2S0 13
217+
#define JH7100_CLK_I2S0_BCLK 14
218+
#define JH7100_CLK_I2S0_BCLK_INV 15
219+
#define JH7100_CLK_I2S0_LRCLK 16
220+
#define JH7100_CLK_APB_I2S1 17
221+
#define JH7100_CLK_I2S1_BCLK 18
222+
#define JH7100_CLK_I2S1_BCLK_INV 19
223+
#define JH7100_CLK_I2S1_LRCLK 20
224+
#define JH7100_CLK_APB_I2SDAC16K 21
225+
#define JH7100_CLK_APB0_BUS 22
226+
#define JH7100_CLK_DMA1P_AHB 23
227+
#define JH7100_CLK_APB_USB 24
228+
#define JH7100_CLK_USB_LPM 25
229+
#define JH7100_CLK_USB_STB 26
230+
231+
#define JH7100_CLK_ADC_BCLK_IOPAD 27
232+
#define JH7100_CLK_ADC_LRCLK_IOPAD 28
233+
#define JH7100_CLK_DAC_BCLK_IOPAD 29
234+
#define JH7100_CLK_DAC_LRCLK_IOPAD 30
235+
#define JH7100_CLK_CODEC_EXT 31
236+
#define JH7100_CLK_AUD_12288 32
237+
#define JH7100_CLK_AUD_END 33
238+
202239
#endif /* __DT_BINDINGS_CLOCK_STARFIVE_JH7100_H__ */

include/dt-bindings/reset/starfive-jh7100.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,27 @@
123123

124124
#define JH7100_RSTN_END 114
125125

126+
/* audio resets */
127+
#define JH7100_AUDRSTN_APB_BUS 0
128+
#define JH7100_AUDRSTN_APB_I2SADC 1
129+
#define JH7100_AUDRSTN_I2SADC_SRST 2
130+
#define JH7100_AUDRSTN_APB_PDM 3
131+
#define JH7100_AUDRSTN_APB_I2SVAD 4
132+
#define JH7100_AUDRSTN_I2SVAD_SRST 5
133+
#define JH7100_AUDRSTN_APB_SPDIF 6
134+
#define JH7100_AUDRSTN_APB_PWMDAC 7
135+
#define JH7100_AUDRSTN_APB_I2SDAC 8
136+
#define JH7100_AUDRSTN_I2SDAC_SRST 9
137+
#define JH7100_AUDRSTN_APB_I2S1 10
138+
#define JH7100_AUDRSTN_I2S1_SRST 11
139+
#define JH7100_AUDRSTN_APB_I2SDAC16K 12
140+
#define JH7100_AUDRSTN_I2SDAC16K_SRST 13
141+
#define JH7100_AUDRSTN_DMA1P_AHB 14
142+
#define JH7100_AUDRSTN_APB_USB 15
143+
#define JH7100_AUDRSTN_AXI_USB 16
144+
#define JH7100_AUDRSTN_USB_PWRUP 17
145+
#define JH7100_AUDRSTN_USB_PONRST 18
146+
147+
#define JH7100_AUDIO_RSTN_END 19
148+
126149
#endif /* __DT_BINDINGS_RESET_STARFIVE_JH7100_H__ */

0 commit comments

Comments
 (0)