Skip to content

Commit b14cbdf

Browse files
linuswbebarino
authored andcommitted
clk: ux500: Add driver for the reset portions of PRCC
The Ux500 PRCC (peripheral reset and clock controller) can also control reset of the IP blocks, not just clocks. As the PRCC is probed as a clock controller and we have other platforms implementing combined clock and reset controllers, follow this pattern and implement the PRCC rest controller as part of the clock driver. The reset controller needs to be selected from the machine as Ux500 has traditionally selected its mandatory subsystem prerequisites from there. Cc: Philipp Zabel <[email protected]> Cc: Ulf Hansson <[email protected]> Signed-off-by: Linus Walleij <[email protected]> Link: https://lore.kernel.org/r/[email protected] Acked-by: Ulf Hansson <[email protected]> [[email protected]: Dropped allocation error message] Signed-off-by: Stephen Boyd <[email protected]>
1 parent f2b883b commit b14cbdf

File tree

6 files changed

+244
-13
lines changed

6 files changed

+244
-13
lines changed

arch/arm/mach-ux500/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ menuconfig ARCH_U8500
2929
select REGULATOR_DB8500_PRCMU
3030
select REGULATOR_FIXED_VOLTAGE
3131
select SOC_BUS
32+
select RESET_CONTROLLER
3233
help
3334
Support for ST-Ericsson's Ux500 architecture
3435

drivers/clk/ux500/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ obj-y += clk-prcc.o
88
obj-y += clk-prcmu.o
99
obj-y += clk-sysctrl.o
1010

11+
# Reset control
12+
obj-y += reset-prcc.o
13+
1114
# Clock definitions
1215
obj-y += u8500_of_clk.o
1316

drivers/clk/ux500/prcc.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
3+
#ifndef __PRCC_H
4+
#define __PRCC_H
5+
6+
#define PRCC_NUM_PERIPH_CLUSTERS 6
7+
#define PRCC_PERIPHS_PER_CLUSTER 32
8+
9+
/* CLKRST4 is missing making it hard to index things */
10+
enum clkrst_index {
11+
CLKRST1_INDEX = 0,
12+
CLKRST2_INDEX,
13+
CLKRST3_INDEX,
14+
CLKRST5_INDEX,
15+
CLKRST6_INDEX,
16+
CLKRST_MAX,
17+
};
18+
19+
#endif

drivers/clk/ux500/reset-prcc.c

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Reset controller portions for the U8500 PRCC
4+
* Copyright (C) 2021 Linus Walleij <[email protected]>
5+
*/
6+
#include <linux/of.h>
7+
#include <linux/of_address.h>
8+
#include <linux/slab.h>
9+
#include <linux/io.h>
10+
#include <linux/err.h>
11+
#include <linux/types.h>
12+
#include <linux/reset-controller.h>
13+
#include <linux/bits.h>
14+
#include <linux/delay.h>
15+
16+
#include "prcc.h"
17+
#include "reset-prcc.h"
18+
19+
#define to_u8500_prcc_reset(p) container_of((p), struct u8500_prcc_reset, rcdev)
20+
21+
/* This macro flattens the 2-dimensional PRCC numberspace */
22+
#define PRCC_RESET_LINE(prcc_num, bit) \
23+
(((prcc_num) * PRCC_PERIPHS_PER_CLUSTER) + (bit))
24+
25+
/*
26+
* Reset registers in each PRCC - the reset lines are active low
27+
* so what you need to do is write a bit for the peripheral you
28+
* want to put into reset into the CLEAR register, this will assert
29+
* the reset by pulling the line low. SET take the device out of
30+
* reset. The status reflects the actual state of the line.
31+
*/
32+
#define PRCC_K_SOFTRST_SET 0x018
33+
#define PRCC_K_SOFTRST_CLEAR 0x01c
34+
#define PRCC_K_RST_STATUS 0x020
35+
36+
static int prcc_num_to_index(unsigned int num)
37+
{
38+
switch (num) {
39+
case 1:
40+
return CLKRST1_INDEX;
41+
case 2:
42+
return CLKRST2_INDEX;
43+
case 3:
44+
return CLKRST3_INDEX;
45+
case 5:
46+
return CLKRST5_INDEX;
47+
case 6:
48+
return CLKRST6_INDEX;
49+
}
50+
return -EINVAL;
51+
}
52+
53+
static void __iomem *u8500_prcc_reset_base(struct u8500_prcc_reset *ur,
54+
unsigned long id)
55+
{
56+
unsigned int prcc_num, index;
57+
58+
prcc_num = id / PRCC_PERIPHS_PER_CLUSTER;
59+
index = prcc_num_to_index(prcc_num);
60+
61+
if (index > ARRAY_SIZE(ur->base))
62+
return NULL;
63+
64+
return ur->base[index];
65+
}
66+
67+
static int u8500_prcc_reset(struct reset_controller_dev *rcdev,
68+
unsigned long id)
69+
{
70+
struct u8500_prcc_reset *ur = to_u8500_prcc_reset(rcdev);
71+
void __iomem *base = u8500_prcc_reset_base(ur, id);
72+
unsigned int bit = id % PRCC_PERIPHS_PER_CLUSTER;
73+
74+
pr_debug("PRCC cycle reset id %lu, bit %u\n", id, bit);
75+
76+
/*
77+
* Assert reset and then release it. The one microsecond
78+
* delay is found in the vendor reference code.
79+
*/
80+
writel(BIT(bit), base + PRCC_K_SOFTRST_CLEAR);
81+
udelay(1);
82+
writel(BIT(bit), base + PRCC_K_SOFTRST_SET);
83+
udelay(1);
84+
85+
return 0;
86+
}
87+
88+
static int u8500_prcc_reset_assert(struct reset_controller_dev *rcdev,
89+
unsigned long id)
90+
{
91+
struct u8500_prcc_reset *ur = to_u8500_prcc_reset(rcdev);
92+
void __iomem *base = u8500_prcc_reset_base(ur, id);
93+
unsigned int bit = id % PRCC_PERIPHS_PER_CLUSTER;
94+
95+
pr_debug("PRCC assert reset id %lu, bit %u\n", id, bit);
96+
writel(BIT(bit), base + PRCC_K_SOFTRST_CLEAR);
97+
98+
return 0;
99+
}
100+
101+
static int u8500_prcc_reset_deassert(struct reset_controller_dev *rcdev,
102+
unsigned long id)
103+
{
104+
struct u8500_prcc_reset *ur = to_u8500_prcc_reset(rcdev);
105+
void __iomem *base = u8500_prcc_reset_base(ur, id);
106+
unsigned int bit = id % PRCC_PERIPHS_PER_CLUSTER;
107+
108+
pr_debug("PRCC deassert reset id %lu, bit %u\n", id, bit);
109+
writel(BIT(bit), base + PRCC_K_SOFTRST_SET);
110+
111+
return 0;
112+
}
113+
114+
static int u8500_prcc_reset_status(struct reset_controller_dev *rcdev,
115+
unsigned long id)
116+
{
117+
struct u8500_prcc_reset *ur = to_u8500_prcc_reset(rcdev);
118+
void __iomem *base = u8500_prcc_reset_base(ur, id);
119+
unsigned int bit = id % PRCC_PERIPHS_PER_CLUSTER;
120+
u32 val;
121+
122+
pr_debug("PRCC check status on reset line id %lu, bit %u\n", id, bit);
123+
val = readl(base + PRCC_K_RST_STATUS);
124+
125+
/* Active low so return the inverse value of the bit */
126+
return !(val & BIT(bit));
127+
}
128+
129+
static const struct reset_control_ops u8500_prcc_reset_ops = {
130+
.reset = u8500_prcc_reset,
131+
.assert = u8500_prcc_reset_assert,
132+
.deassert = u8500_prcc_reset_deassert,
133+
.status = u8500_prcc_reset_status,
134+
};
135+
136+
static int u8500_prcc_reset_xlate(struct reset_controller_dev *rcdev,
137+
const struct of_phandle_args *reset_spec)
138+
{
139+
unsigned int prcc_num, bit;
140+
141+
if (reset_spec->args_count != 2)
142+
return -EINVAL;
143+
144+
prcc_num = reset_spec->args[0];
145+
bit = reset_spec->args[1];
146+
147+
if (prcc_num != 1 && prcc_num != 2 && prcc_num != 3 &&
148+
prcc_num != 5 && prcc_num != 6) {
149+
pr_err("%s: invalid PRCC %d\n", __func__, prcc_num);
150+
return -EINVAL;
151+
}
152+
153+
pr_debug("located reset line %d at PRCC %d bit %d\n",
154+
PRCC_RESET_LINE(prcc_num, bit), prcc_num, bit);
155+
156+
return PRCC_RESET_LINE(prcc_num, bit);
157+
}
158+
159+
void u8500_prcc_reset_init(struct device_node *np, struct u8500_prcc_reset *ur)
160+
{
161+
struct reset_controller_dev *rcdev = &ur->rcdev;
162+
int ret;
163+
int i;
164+
165+
for (i = 0; i < CLKRST_MAX; i++) {
166+
ur->base[i] = ioremap(ur->phy_base[i], SZ_4K);
167+
if (!ur->base[i])
168+
pr_err("PRCC failed to remap for reset base %d (%08x)\n",
169+
i, ur->phy_base[i]);
170+
}
171+
172+
rcdev->owner = THIS_MODULE;
173+
rcdev->ops = &u8500_prcc_reset_ops;
174+
rcdev->of_node = np;
175+
rcdev->of_reset_n_cells = 2;
176+
rcdev->of_xlate = u8500_prcc_reset_xlate;
177+
178+
ret = reset_controller_register(rcdev);
179+
if (ret)
180+
pr_err("PRCC failed to register reset controller\n");
181+
}

drivers/clk/ux500/reset-prcc.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
3+
#ifndef __RESET_PRCC_H
4+
#define __RESET_PRCC_H
5+
6+
#include <linux/reset-controller.h>
7+
#include <linux/io.h>
8+
9+
/**
10+
* struct u8500_prcc_reset - U8500 PRCC reset controller state
11+
* @rcdev: reset controller device
12+
* @phy_base: the physical base address for each PRCC block
13+
* @base: the remapped PRCC bases
14+
*/
15+
struct u8500_prcc_reset {
16+
struct reset_controller_dev rcdev;
17+
u32 phy_base[CLKRST_MAX];
18+
void __iomem *base[CLKRST_MAX];
19+
};
20+
21+
void u8500_prcc_reset_init(struct device_node *np, struct u8500_prcc_reset *ur);
22+
23+
#endif

drivers/clk/ux500/u8500_of_clk.c

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
#include <linux/of_address.h>
1111
#include <linux/clk-provider.h>
1212
#include <linux/mfd/dbx500-prcmu.h>
13-
#include "clk.h"
1413

15-
#define PRCC_NUM_PERIPH_CLUSTERS 6
16-
#define PRCC_PERIPHS_PER_CLUSTER 32
14+
#include "clk.h"
15+
#include "prcc.h"
16+
#include "reset-prcc.h"
1717

1818
static struct clk *prcmu_clk[PRCMU_NUM_CLKS];
1919
static struct clk *prcc_pclk[(PRCC_NUM_PERIPH_CLUSTERS + 1) * PRCC_PERIPHS_PER_CLUSTER];
@@ -46,25 +46,25 @@ static struct clk *ux500_twocell_get(struct of_phandle_args *clkspec,
4646
return PRCC_SHOW(clk_data, base, bit);
4747
}
4848

49-
/* CLKRST4 is missing making it hard to index things */
50-
enum clkrst_index {
51-
CLKRST1_INDEX = 0,
52-
CLKRST2_INDEX,
53-
CLKRST3_INDEX,
54-
CLKRST5_INDEX,
55-
CLKRST6_INDEX,
56-
CLKRST_MAX,
57-
};
58-
5949
static void u8500_clk_init(struct device_node *np)
6050
{
6151
struct prcmu_fw_version *fw_version;
6252
struct device_node *child = NULL;
6353
const char *sgaclk_parent = NULL;
6454
struct clk *clk, *rtc_clk, *twd_clk;
6555
u32 bases[CLKRST_MAX];
56+
struct u8500_prcc_reset *rstc;
6657
int i;
6758

59+
/*
60+
* We allocate the reset controller here so that we can fill in the
61+
* base addresses properly and pass to the reset controller init
62+
* function later on.
63+
*/
64+
rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
65+
if (!rstc)
66+
return;
67+
6868
for (i = 0; i < ARRAY_SIZE(bases); i++) {
6969
struct resource r;
7070

@@ -73,6 +73,7 @@ static void u8500_clk_init(struct device_node *np)
7373
pr_err("failed to get CLKRST %d base address\n",
7474
i + 1);
7575
bases[i] = r.start;
76+
rstc->phy_base[i] = r.start;
7677
}
7778

7879
/* Clock sources */
@@ -563,6 +564,9 @@ static void u8500_clk_init(struct device_node *np)
563564

564565
if (of_node_name_eq(child, "smp-twd-clock"))
565566
of_clk_add_provider(child, of_clk_src_simple_get, twd_clk);
567+
568+
if (of_node_name_eq(child, "prcc-reset-controller"))
569+
u8500_prcc_reset_init(child, rstc);
566570
}
567571
}
568572
CLK_OF_DECLARE(u8500_clks, "stericsson,u8500-clks", u8500_clk_init);

0 commit comments

Comments
 (0)