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_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
59struct 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 */
69static 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 */
90static 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
104static 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(map: rst->sys_regs, reg: info->base, mask: info->mask, val: 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
120static 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(map: rst->sys_regs, reg: info->base,
130 mask: info->mask, val: high ? info->mask : 0);
131}
132
133static int ccu_rst_assert(struct reset_controller_dev *rcdev,
134 unsigned long idx)
135{
136 return ccu_rst_set(rcdev, idx, high: true);
137}
138
139static int ccu_rst_deassert(struct reset_controller_dev *rcdev,
140 unsigned long idx)
141{
142 return ccu_rst_set(rcdev, idx, high: false);
143}
144
145static 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(map: rst->sys_regs, reg: info->base, val: &val);
156
157 return !!(val & info->mask);
158}
159
160static 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
167struct 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(error: -EINVAL);
174
175 rst = kzalloc(size: sizeof(*rst), GFP_KERNEL);
176 if (!rst)
177 return ERR_PTR(error: -ENOMEM);
178
179 rst->sys_regs = rst_init->sys_regs;
180 if (of_device_is_compatible(device: 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(device: 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(rcdev: &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
206err_kfree_rst:
207 kfree(objp: rst);
208
209 return ERR_PTR(error: ret);
210}
211
212void ccu_rst_hw_unregister(struct ccu_rst *rst)
213{
214 reset_controller_unregister(rcdev: &rst->rcdev);
215
216 kfree(objp: rst);
217}
218

source code of linux/drivers/clk/baikal-t1/ccu-rst.c