Skip to content

Commit 70fa895

Browse files
fancerbebarino
authored andcommitted
clk: baikal-t1: Move reset-controls code into a dedicated module
Before adding the directly controlled resets support it's reasonable to move the existing resets control functionality into a dedicated object for the sake of the CCU dividers clock driver simplification. After the new functionality was added clk-ccu-div.c would have got to a mixture of the weakly dependent clocks and resets methods. Splitting the methods up into the two objects will make the code easier to read and maintain. It shall also improve the code scalability (though hopefully we won't need this part that much in the future). The reset control functionality is now implemented in the framework of a single unit since splitting it up doesn't make much sense due to relatively simple reset operations. The ccu-rst.c has been designed to be looking like ccu-div.c or ccu-pll.c with two globally available methods for the sake of the code unification and better code readability. This commit doesn't provide any change in the CCU reset implementation semantics. As before the driver will support the trigger-like CCU resets only, which are responsible for the AXI-bus, APB-bus and SATA-ref blocks reset. The assert/de-assert-capable reset controls support will be added in the next commit. Note the CCU Clock dividers and resets functionality split up was possible due to not having any side-effects (at least we didn't found ones) of the regmap-based concurrent access of the common CCU dividers/reset CSRs. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de> Link: https://lore.kernel.org/r/20220929225402.9696-6-Sergey.Semin@baikalelectronics.ru Signed-off-by: Stephen Boyd <sboyd@kernel.org>
1 parent 081a9b7 commit 70fa895

File tree

7 files changed

+231
-105
lines changed

7 files changed

+231
-105
lines changed

drivers/clk/baikal-t1/Kconfig

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ config CLK_BT1_CCU_PLL
2929

3030
config CLK_BT1_CCU_DIV
3131
bool "Baikal-T1 CCU Dividers support"
32-
select RESET_CONTROLLER
3332
select MFD_SYSCON
3433
default MIPS_BAIKAL_T1
3534
help
@@ -39,4 +38,15 @@ config CLK_BT1_CCU_DIV
3938
either gateable or ungateable. Some of the CCU dividers can be as well
4039
used to reset the domains they're supplying clock to.
4140

41+
config CLK_BT1_CCU_RST
42+
bool "Baikal-T1 CCU Resets support"
43+
select RESET_CONTROLLER
44+
select MFD_SYSCON
45+
default MIPS_BAIKAL_T1
46+
help
47+
Enable this to support the CCU reset blocks responsible for the
48+
AXI-bus and some subsystems reset. These are mainly the
49+
self-deasserted reset controls but there are several lines which
50+
can be directly asserted/de-asserted (PCIe and DDR sub-domains).
51+
4252
endif

drivers/clk/baikal-t1/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
obj-$(CONFIG_CLK_BT1_CCU_PLL) += ccu-pll.o clk-ccu-pll.o
33
obj-$(CONFIG_CLK_BT1_CCU_DIV) += ccu-div.o clk-ccu-div.o
4+
obj-$(CONFIG_CLK_BT1_CCU_RST) += ccu-rst.o

drivers/clk/baikal-t1/ccu-div.c

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
#define CCU_DIV_CTL_GATE_REF_BUF BIT(28)
3838
#define CCU_DIV_CTL_LOCK_NORMAL BIT(31)
3939

40-
#define CCU_DIV_RST_DELAY_US 1
4140
#define CCU_DIV_LOCK_CHECK_RETRIES 50
4241

4342
#define CCU_DIV_CLKDIV_MIN 0
@@ -323,24 +322,6 @@ static int ccu_div_fixed_set_rate(struct clk_hw *hw, unsigned long rate,
323322
return 0;
324323
}
325324

326-
int ccu_div_reset_domain(struct ccu_div *div)
327-
{
328-
unsigned long flags;
329-
330-
if (!div || !(div->features & CCU_DIV_RESET_DOMAIN))
331-
return -EINVAL;
332-
333-
spin_lock_irqsave(&div->lock, flags);
334-
regmap_update_bits(div->sys_regs, div->reg_ctl,
335-
CCU_DIV_CTL_RST, CCU_DIV_CTL_RST);
336-
spin_unlock_irqrestore(&div->lock, flags);
337-
338-
/* The next delay must be enough to cover all the resets. */
339-
udelay(CCU_DIV_RST_DELAY_US);
340-
341-
return 0;
342-
}
343-
344325
#ifdef CONFIG_DEBUG_FS
345326

346327
struct ccu_div_dbgfs_bit {

drivers/clk/baikal-t1/ccu-div.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
* @CCU_DIV_SKIP_ONE_TO_THREE: For some reason divider can't be within [1,3].
2929
* It can be either 0 or greater than 3.
3030
* @CCU_DIV_LOCK_SHIFTED: Find lock-bit at non-standard position.
31-
* @CCU_DIV_RESET_DOMAIN: Provide reset clock domain method.
31+
* @CCU_DIV_RESET_DOMAIN: There is a clock domain reset handle.
3232
*/
3333
#define CCU_DIV_SKIP_ONE BIT(1)
3434
#define CCU_DIV_SKIP_ONE_TO_THREE BIT(2)
@@ -115,6 +115,4 @@ struct ccu_div *ccu_div_hw_register(const struct ccu_div_init_data *init);
115115

116116
void ccu_div_hw_unregister(struct ccu_div *div);
117117

118-
int ccu_div_reset_domain(struct ccu_div *div);
119-
120118
#endif /* __CLK_BT1_CCU_DIV_H__ */

drivers/clk/baikal-t1/ccu-rst.c

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (C) 2021 BAIKAL ELECTRONICS, JSC
4+
*
5+
* Authors:
6+
* Serge Semin <Sergey.Semin@baikalelectronics.ru>
7+
*
8+
* Baikal-T1 CCU Resets interface driver
9+
*/
10+
11+
#define pr_fmt(fmt) "bt1-ccu-rst: " fmt
12+
13+
#include <linux/bits.h>
14+
#include <linux/delay.h>
15+
#include <linux/kernel.h>
16+
#include <linux/of.h>
17+
#include <linux/printk.h>
18+
#include <linux/regmap.h>
19+
#include <linux/reset-controller.h>
20+
#include <linux/slab.h>
21+
22+
#include <dt-bindings/reset/bt1-ccu.h>
23+
24+
#include "ccu-rst.h"
25+
26+
#define CCU_AXI_MAIN_BASE 0x030
27+
#define CCU_AXI_DDR_BASE 0x034
28+
#define CCU_AXI_SATA_BASE 0x038
29+
#define CCU_AXI_GMAC0_BASE 0x03C
30+
#define CCU_AXI_GMAC1_BASE 0x040
31+
#define CCU_AXI_XGMAC_BASE 0x044
32+
#define CCU_AXI_PCIE_M_BASE 0x048
33+
#define CCU_AXI_PCIE_S_BASE 0x04C
34+
#define CCU_AXI_USB_BASE 0x050
35+
#define CCU_AXI_HWA_BASE 0x054
36+
#define CCU_AXI_SRAM_BASE 0x058
37+
38+
#define CCU_SYS_SATA_REF_BASE 0x060
39+
#define CCU_SYS_APB_BASE 0x064
40+
41+
#define CCU_RST_DELAY_US 1
42+
43+
#define CCU_RST_TRIG(_base, _ofs) \
44+
{ \
45+
.base = _base, \
46+
.mask = BIT(_ofs), \
47+
}
48+
49+
struct ccu_rst_info {
50+
unsigned int base;
51+
unsigned int mask;
52+
};
53+
54+
/*
55+
* Each AXI-bus clock divider is equipped with the corresponding clock-consumer
56+
* domain reset (it's self-deasserted reset control).
57+
*/
58+
static const struct ccu_rst_info axi_rst_info[] = {
59+
[CCU_AXI_MAIN_RST] = CCU_RST_TRIG(CCU_AXI_MAIN_BASE, 1),
60+
[CCU_AXI_DDR_RST] = CCU_RST_TRIG(CCU_AXI_DDR_BASE, 1),
61+
[CCU_AXI_SATA_RST] = CCU_RST_TRIG(CCU_AXI_SATA_BASE, 1),
62+
[CCU_AXI_GMAC0_RST] = CCU_RST_TRIG(CCU_AXI_GMAC0_BASE, 1),
63+
[CCU_AXI_GMAC1_RST] = CCU_RST_TRIG(CCU_AXI_GMAC1_BASE, 1),
64+
[CCU_AXI_XGMAC_RST] = CCU_RST_TRIG(CCU_AXI_XGMAC_BASE, 1),
65+
[CCU_AXI_PCIE_M_RST] = CCU_RST_TRIG(CCU_AXI_PCIE_M_BASE, 1),
66+
[CCU_AXI_PCIE_S_RST] = CCU_RST_TRIG(CCU_AXI_PCIE_S_BASE, 1),
67+
[CCU_AXI_USB_RST] = CCU_RST_TRIG(CCU_AXI_USB_BASE, 1),
68+
[CCU_AXI_HWA_RST] = CCU_RST_TRIG(CCU_AXI_HWA_BASE, 1),
69+
[CCU_AXI_SRAM_RST] = CCU_RST_TRIG(CCU_AXI_SRAM_BASE, 1),
70+
};
71+
72+
/*
73+
* SATA reference clock domain and APB-bus domain are connected with the
74+
* sefl-deasserted reset control, which can be activated via the corresponding
75+
* clock divider register. DDR and PCIe sub-domains can be reset with directly
76+
* controlled reset signals. Resetting the DDR controller though won't end up
77+
* well while the Linux kernel is working.
78+
*/
79+
static const struct ccu_rst_info sys_rst_info[] = {
80+
[CCU_SYS_SATA_REF_RST] = CCU_RST_TRIG(CCU_SYS_SATA_REF_BASE, 1),
81+
[CCU_SYS_APB_RST] = CCU_RST_TRIG(CCU_SYS_APB_BASE, 1),
82+
};
83+
84+
static int ccu_rst_reset(struct reset_controller_dev *rcdev, unsigned long idx)
85+
{
86+
struct ccu_rst *rst = to_ccu_rst(rcdev);
87+
const struct ccu_rst_info *info = &rst->rsts_info[idx];
88+
89+
regmap_update_bits(rst->sys_regs, info->base, info->mask, info->mask);
90+
91+
/* The next delay must be enough to cover all the resets. */
92+
udelay(CCU_RST_DELAY_US);
93+
94+
return 0;
95+
}
96+
97+
static const struct reset_control_ops ccu_rst_ops = {
98+
.reset = ccu_rst_reset,
99+
};
100+
101+
struct ccu_rst *ccu_rst_hw_register(const struct ccu_rst_init_data *rst_init)
102+
{
103+
struct ccu_rst *rst;
104+
int ret;
105+
106+
if (!rst_init)
107+
return ERR_PTR(-EINVAL);
108+
109+
rst = kzalloc(sizeof(*rst), GFP_KERNEL);
110+
if (!rst)
111+
return ERR_PTR(-ENOMEM);
112+
113+
rst->sys_regs = rst_init->sys_regs;
114+
if (of_device_is_compatible(rst_init->np, "baikal,bt1-ccu-axi")) {
115+
rst->rcdev.nr_resets = ARRAY_SIZE(axi_rst_info);
116+
rst->rsts_info = axi_rst_info;
117+
} else if (of_device_is_compatible(rst_init->np, "baikal,bt1-ccu-sys")) {
118+
rst->rcdev.nr_resets = ARRAY_SIZE(sys_rst_info);
119+
rst->rsts_info = sys_rst_info;
120+
} else {
121+
pr_err("Incompatible DT node '%s' specified\n",
122+
of_node_full_name(rst_init->np));
123+
ret = -EINVAL;
124+
goto err_kfree_rst;
125+
}
126+
127+
rst->rcdev.owner = THIS_MODULE;
128+
rst->rcdev.ops = &ccu_rst_ops;
129+
rst->rcdev.of_node = rst_init->np;
130+
131+
ret = reset_controller_register(&rst->rcdev);
132+
if (ret) {
133+
pr_err("Couldn't register '%s' reset controller\n",
134+
of_node_full_name(rst_init->np));
135+
goto err_kfree_rst;
136+
}
137+
138+
return rst;
139+
140+
err_kfree_rst:
141+
kfree(rst);
142+
143+
return ERR_PTR(ret);
144+
}
145+
146+
void ccu_rst_hw_unregister(struct ccu_rst *rst)
147+
{
148+
reset_controller_unregister(&rst->rcdev);
149+
150+
kfree(rst);
151+
}

drivers/clk/baikal-t1/ccu-rst.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (C) 2021 BAIKAL ELECTRONICS, JSC
4+
*
5+
* Baikal-T1 CCU Resets interface driver
6+
*/
7+
#ifndef __CLK_BT1_CCU_RST_H__
8+
#define __CLK_BT1_CCU_RST_H__
9+
10+
#include <linux/of.h>
11+
#include <linux/regmap.h>
12+
#include <linux/reset-controller.h>
13+
14+
struct ccu_rst_info;
15+
16+
/*
17+
* struct ccu_rst_init_data - CCU Resets initialization data
18+
* @sys_regs: Baikal-T1 System Controller registers map.
19+
* @np: Pointer to the node with the System CCU block.
20+
*/
21+
struct ccu_rst_init_data {
22+
struct regmap *sys_regs;
23+
struct device_node *np;
24+
};
25+
26+
/*
27+
* struct ccu_rst - CCU Reset descriptor
28+
* @rcdev: Reset controller descriptor.
29+
* @sys_regs: Baikal-T1 System Controller registers map.
30+
* @rsts_info: Reset flag info (base address and mask).
31+
*/
32+
struct ccu_rst {
33+
struct reset_controller_dev rcdev;
34+
struct regmap *sys_regs;
35+
const struct ccu_rst_info *rsts_info;
36+
};
37+
#define to_ccu_rst(_rcdev) container_of(_rcdev, struct ccu_rst, rcdev)
38+
39+
#ifdef CONFIG_CLK_BT1_CCU_RST
40+
41+
struct ccu_rst *ccu_rst_hw_register(const struct ccu_rst_init_data *init);
42+
43+
void ccu_rst_hw_unregister(struct ccu_rst *rst);
44+
45+
#else
46+
47+
static inline
48+
struct ccu_rst *ccu_rst_hw_register(const struct ccu_rst_init_data *init)
49+
{
50+
return NULL;
51+
}
52+
53+
static inline void ccu_rst_hw_unregister(struct ccu_rst *rst) {}
54+
55+
#endif
56+
57+
#endif /* __CLK_BT1_CCU_RST_H__ */

0 commit comments

Comments
 (0)