Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/clk/baikal-t1/ccu-rst.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright (C) 2021 BAIKAL ELECTRONICS, JSC
4
*
5
* Authors:
6
* Serge Semin <[email protected]>
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_DDR_BASE 0x02c
39
#define CCU_SYS_SATA_REF_BASE 0x060
40
#define CCU_SYS_APB_BASE 0x064
41
#define CCU_SYS_PCIE_BASE 0x144
42
43
#define CCU_RST_DELAY_US 1
44
45
#define CCU_RST_TRIG(_base, _ofs) \
46
{ \
47
.type = CCU_RST_TRIG, \
48
.base = _base, \
49
.mask = BIT(_ofs), \
50
}
51
52
#define CCU_RST_DIR(_base, _ofs) \
53
{ \
54
.type = CCU_RST_DIR, \
55
.base = _base, \
56
.mask = BIT(_ofs), \
57
}
58
59
struct ccu_rst_info {
60
enum ccu_rst_type type;
61
unsigned int base;
62
unsigned int mask;
63
};
64
65
/*
66
* Each AXI-bus clock divider is equipped with the corresponding clock-consumer
67
* domain reset (it's self-deasserted reset control).
68
*/
69
static const struct ccu_rst_info axi_rst_info[] = {
70
[CCU_AXI_MAIN_RST] = CCU_RST_TRIG(CCU_AXI_MAIN_BASE, 1),
71
[CCU_AXI_DDR_RST] = CCU_RST_TRIG(CCU_AXI_DDR_BASE, 1),
72
[CCU_AXI_SATA_RST] = CCU_RST_TRIG(CCU_AXI_SATA_BASE, 1),
73
[CCU_AXI_GMAC0_RST] = CCU_RST_TRIG(CCU_AXI_GMAC0_BASE, 1),
74
[CCU_AXI_GMAC1_RST] = CCU_RST_TRIG(CCU_AXI_GMAC1_BASE, 1),
75
[CCU_AXI_XGMAC_RST] = CCU_RST_TRIG(CCU_AXI_XGMAC_BASE, 1),
76
[CCU_AXI_PCIE_M_RST] = CCU_RST_TRIG(CCU_AXI_PCIE_M_BASE, 1),
77
[CCU_AXI_PCIE_S_RST] = CCU_RST_TRIG(CCU_AXI_PCIE_S_BASE, 1),
78
[CCU_AXI_USB_RST] = CCU_RST_TRIG(CCU_AXI_USB_BASE, 1),
79
[CCU_AXI_HWA_RST] = CCU_RST_TRIG(CCU_AXI_HWA_BASE, 1),
80
[CCU_AXI_SRAM_RST] = CCU_RST_TRIG(CCU_AXI_SRAM_BASE, 1),
81
};
82
83
/*
84
* SATA reference clock domain and APB-bus domain are connected with the
85
* sefl-deasserted reset control, which can be activated via the corresponding
86
* clock divider register. DDR and PCIe sub-domains can be reset with directly
87
* controlled reset signals. Resetting the DDR controller though won't end up
88
* well while the Linux kernel is working.
89
*/
90
static const struct ccu_rst_info sys_rst_info[] = {
91
[CCU_SYS_SATA_REF_RST] = CCU_RST_TRIG(CCU_SYS_SATA_REF_BASE, 1),
92
[CCU_SYS_APB_RST] = CCU_RST_TRIG(CCU_SYS_APB_BASE, 1),
93
[CCU_SYS_DDR_FULL_RST] = CCU_RST_DIR(CCU_SYS_DDR_BASE, 1),
94
[CCU_SYS_DDR_INIT_RST] = CCU_RST_DIR(CCU_SYS_DDR_BASE, 2),
95
[CCU_SYS_PCIE_PCS_PHY_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 0),
96
[CCU_SYS_PCIE_PIPE0_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 4),
97
[CCU_SYS_PCIE_CORE_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 8),
98
[CCU_SYS_PCIE_PWR_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 9),
99
[CCU_SYS_PCIE_STICKY_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 10),
100
[CCU_SYS_PCIE_NSTICKY_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 11),
101
[CCU_SYS_PCIE_HOT_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 12),
102
};
103
104
static int ccu_rst_reset(struct reset_controller_dev *rcdev, unsigned long idx)
105
{
106
struct ccu_rst *rst = to_ccu_rst(rcdev);
107
const struct ccu_rst_info *info = &rst->rsts_info[idx];
108
109
if (info->type != CCU_RST_TRIG)
110
return -EOPNOTSUPP;
111
112
regmap_update_bits(rst->sys_regs, info->base, info->mask, info->mask);
113
114
/* The next delay must be enough to cover all the resets. */
115
udelay(CCU_RST_DELAY_US);
116
117
return 0;
118
}
119
120
static int ccu_rst_set(struct reset_controller_dev *rcdev,
121
unsigned long idx, bool high)
122
{
123
struct ccu_rst *rst = to_ccu_rst(rcdev);
124
const struct ccu_rst_info *info = &rst->rsts_info[idx];
125
126
if (info->type != CCU_RST_DIR)
127
return high ? -EOPNOTSUPP : 0;
128
129
return regmap_update_bits(rst->sys_regs, info->base,
130
info->mask, high ? info->mask : 0);
131
}
132
133
static int ccu_rst_assert(struct reset_controller_dev *rcdev,
134
unsigned long idx)
135
{
136
return ccu_rst_set(rcdev, idx, true);
137
}
138
139
static int ccu_rst_deassert(struct reset_controller_dev *rcdev,
140
unsigned long idx)
141
{
142
return ccu_rst_set(rcdev, idx, false);
143
}
144
145
static int ccu_rst_status(struct reset_controller_dev *rcdev,
146
unsigned long idx)
147
{
148
struct ccu_rst *rst = to_ccu_rst(rcdev);
149
const struct ccu_rst_info *info = &rst->rsts_info[idx];
150
u32 val;
151
152
if (info->type != CCU_RST_DIR)
153
return -EOPNOTSUPP;
154
155
regmap_read(rst->sys_regs, info->base, &val);
156
157
return !!(val & info->mask);
158
}
159
160
static const struct reset_control_ops ccu_rst_ops = {
161
.reset = ccu_rst_reset,
162
.assert = ccu_rst_assert,
163
.deassert = ccu_rst_deassert,
164
.status = ccu_rst_status,
165
};
166
167
struct ccu_rst *ccu_rst_hw_register(const struct ccu_rst_init_data *rst_init)
168
{
169
struct ccu_rst *rst;
170
int ret;
171
172
if (!rst_init)
173
return ERR_PTR(-EINVAL);
174
175
rst = kzalloc(sizeof(*rst), GFP_KERNEL);
176
if (!rst)
177
return ERR_PTR(-ENOMEM);
178
179
rst->sys_regs = rst_init->sys_regs;
180
if (of_device_is_compatible(rst_init->np, "baikal,bt1-ccu-axi")) {
181
rst->rcdev.nr_resets = ARRAY_SIZE(axi_rst_info);
182
rst->rsts_info = axi_rst_info;
183
} else if (of_device_is_compatible(rst_init->np, "baikal,bt1-ccu-sys")) {
184
rst->rcdev.nr_resets = ARRAY_SIZE(sys_rst_info);
185
rst->rsts_info = sys_rst_info;
186
} else {
187
pr_err("Incompatible DT node '%s' specified\n",
188
of_node_full_name(rst_init->np));
189
ret = -EINVAL;
190
goto err_kfree_rst;
191
}
192
193
rst->rcdev.owner = THIS_MODULE;
194
rst->rcdev.ops = &ccu_rst_ops;
195
rst->rcdev.of_node = rst_init->np;
196
197
ret = reset_controller_register(&rst->rcdev);
198
if (ret) {
199
pr_err("Couldn't register '%s' reset controller\n",
200
of_node_full_name(rst_init->np));
201
goto err_kfree_rst;
202
}
203
204
return rst;
205
206
err_kfree_rst:
207
kfree(rst);
208
209
return ERR_PTR(ret);
210
}
211
212
void ccu_rst_hw_unregister(struct ccu_rst *rst)
213
{
214
reset_controller_unregister(&rst->rcdev);
215
216
kfree(rst);
217
}
218
219