File Index
Files and directories
Sign in
FILE

ccu-rst.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clk/baikal-t1/ccu-rst.c C
  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(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
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(rst->sys_regs, info->base,
130				  info->mask, 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, 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, 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(rst->sys_regs, info->base, &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(-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
206err_kfree_rst:
207	kfree(rst);
208
209	return ERR_PTR(ret);
210}
211
212void ccu_rst_hw_unregister(struct ccu_rst *rst)
213{
214	reset_controller_unregister(&rst->rcdev);
215
216	kfree(rst);
217}
~/ Read-only file preview.