File Index
Files and directories
Sign in
FILE

clk-sg2042-rpgate.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clk/sophgo/clk-sg2042-rpgate.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Sophgo SG2042 RP clock Driver
  4 *
  5 * Copyright (C) 2024 Sophgo Technology Inc.
  6 * Copyright (C) 2024 Chen Wang <unicorn_wang@outlook.com>
  7 */
  8
  9#include <linux/array_size.h>
 10#include <linux/clk-provider.h>
 11#include <linux/platform_device.h>
 12
 13#include <dt-bindings/clock/sophgo,sg2042-rpgate.h>
 14
 15#include "clk-sg2042.h"
 16
 17#define R_SYSGATE_BEGIN		0x0368
 18#define R_RP_RXU_CLK_ENABLE	(0x0368 - R_SYSGATE_BEGIN)
 19#define R_MP0_STATUS_REG	(0x0380 - R_SYSGATE_BEGIN)
 20#define R_MP0_CONTROL_REG	(0x0384 - R_SYSGATE_BEGIN)
 21#define R_MP1_STATUS_REG	(0x0388 - R_SYSGATE_BEGIN)
 22#define R_MP1_CONTROL_REG	(0x038C - R_SYSGATE_BEGIN)
 23#define R_MP2_STATUS_REG	(0x0390 - R_SYSGATE_BEGIN)
 24#define R_MP2_CONTROL_REG	(0x0394 - R_SYSGATE_BEGIN)
 25#define R_MP3_STATUS_REG	(0x0398 - R_SYSGATE_BEGIN)
 26#define R_MP3_CONTROL_REG	(0x039C - R_SYSGATE_BEGIN)
 27#define R_MP4_STATUS_REG	(0x03A0 - R_SYSGATE_BEGIN)
 28#define R_MP4_CONTROL_REG	(0x03A4 - R_SYSGATE_BEGIN)
 29#define R_MP5_STATUS_REG	(0x03A8 - R_SYSGATE_BEGIN)
 30#define R_MP5_CONTROL_REG	(0x03AC - R_SYSGATE_BEGIN)
 31#define R_MP6_STATUS_REG	(0x03B0 - R_SYSGATE_BEGIN)
 32#define R_MP6_CONTROL_REG	(0x03B4 - R_SYSGATE_BEGIN)
 33#define R_MP7_STATUS_REG	(0x03B8 - R_SYSGATE_BEGIN)
 34#define R_MP7_CONTROL_REG	(0x03BC - R_SYSGATE_BEGIN)
 35#define R_MP8_STATUS_REG	(0x03C0 - R_SYSGATE_BEGIN)
 36#define R_MP8_CONTROL_REG	(0x03C4 - R_SYSGATE_BEGIN)
 37#define R_MP9_STATUS_REG	(0x03C8 - R_SYSGATE_BEGIN)
 38#define R_MP9_CONTROL_REG	(0x03CC - R_SYSGATE_BEGIN)
 39#define R_MP10_STATUS_REG	(0x03D0 - R_SYSGATE_BEGIN)
 40#define R_MP10_CONTROL_REG	(0x03D4 - R_SYSGATE_BEGIN)
 41#define R_MP11_STATUS_REG	(0x03D8 - R_SYSGATE_BEGIN)
 42#define R_MP11_CONTROL_REG	(0x03DC - R_SYSGATE_BEGIN)
 43#define R_MP12_STATUS_REG	(0x03E0 - R_SYSGATE_BEGIN)
 44#define R_MP12_CONTROL_REG	(0x03E4 - R_SYSGATE_BEGIN)
 45#define R_MP13_STATUS_REG	(0x03E8 - R_SYSGATE_BEGIN)
 46#define R_MP13_CONTROL_REG	(0x03EC - R_SYSGATE_BEGIN)
 47#define R_MP14_STATUS_REG	(0x03F0 - R_SYSGATE_BEGIN)
 48#define R_MP14_CONTROL_REG	(0x03F4 - R_SYSGATE_BEGIN)
 49#define R_MP15_STATUS_REG	(0x03F8 - R_SYSGATE_BEGIN)
 50#define R_MP15_CONTROL_REG	(0x03FC - R_SYSGATE_BEGIN)
 51
 52/**
 53 * struct sg2042_rpgate_clock - Gate clock for RP(riscv processors) subsystem
 54 * @hw:			clk_hw for initialization
 55 * @id:			used to map clk_onecell_data
 56 * @offset_enable:	offset of gate enable registers
 57 * @bit_idx:		which bit in the register controls gating of this clock
 58 */
 59struct sg2042_rpgate_clock {
 60	struct clk_hw hw;
 61
 62	unsigned int id;
 63
 64	u32 offset_enable;
 65	u8 bit_idx;
 66};
 67
 68/*
 69 * Clock initialization macro naming rules:
 70 * FW: use CLK_HW_INIT_FW_NAME
 71 */
 72#define SG2042_GATE_FW(_id, _name, _parent, _flags,	\
 73		       _r_enable, _bit_idx) {		\
 74		.hw.init = CLK_HW_INIT_FW_NAME(		\
 75				_name,			\
 76				_parent,		\
 77				NULL,			\
 78				_flags),		\
 79		.id = _id,				\
 80		.offset_enable = _r_enable,		\
 81		.bit_idx = _bit_idx,			\
 82	}
 83
 84/*
 85 * Gate clocks for RP subsystem (including the MP subsystem), which control
 86 * registers are defined in SYS_CTRL.
 87 */
 88static const struct sg2042_rpgate_clock sg2042_gate_rp[] = {
 89	/* downstream of clk_gate_rp_cpu_normal about rxu */
 90	SG2042_GATE_FW(GATE_CLK_RXU0, "clk_gate_rxu0", "rpgate",
 91		       0, R_RP_RXU_CLK_ENABLE, 0),
 92	SG2042_GATE_FW(GATE_CLK_RXU1, "clk_gate_rxu1", "rpgate",
 93		       0, R_RP_RXU_CLK_ENABLE, 1),
 94	SG2042_GATE_FW(GATE_CLK_RXU2, "clk_gate_rxu2", "rpgate",
 95		       0, R_RP_RXU_CLK_ENABLE, 2),
 96	SG2042_GATE_FW(GATE_CLK_RXU3, "clk_gate_rxu3", "rpgate",
 97		       0, R_RP_RXU_CLK_ENABLE, 3),
 98	SG2042_GATE_FW(GATE_CLK_RXU4, "clk_gate_rxu4", "rpgate",
 99		       0, R_RP_RXU_CLK_ENABLE, 4),
100	SG2042_GATE_FW(GATE_CLK_RXU5, "clk_gate_rxu5", "rpgate",
101		       0, R_RP_RXU_CLK_ENABLE, 5),
102	SG2042_GATE_FW(GATE_CLK_RXU6, "clk_gate_rxu6", "rpgate",
103		       0, R_RP_RXU_CLK_ENABLE, 6),
104	SG2042_GATE_FW(GATE_CLK_RXU7, "clk_gate_rxu7", "rpgate",
105		       0, R_RP_RXU_CLK_ENABLE, 7),
106	SG2042_GATE_FW(GATE_CLK_RXU8, "clk_gate_rxu8", "rpgate",
107		       0, R_RP_RXU_CLK_ENABLE, 8),
108	SG2042_GATE_FW(GATE_CLK_RXU9, "clk_gate_rxu9", "rpgate",
109		       0, R_RP_RXU_CLK_ENABLE, 9),
110	SG2042_GATE_FW(GATE_CLK_RXU10, "clk_gate_rxu10", "rpgate",
111		       0, R_RP_RXU_CLK_ENABLE, 10),
112	SG2042_GATE_FW(GATE_CLK_RXU11, "clk_gate_rxu11", "rpgate",
113		       0, R_RP_RXU_CLK_ENABLE, 11),
114	SG2042_GATE_FW(GATE_CLK_RXU12, "clk_gate_rxu12", "rpgate",
115		       0, R_RP_RXU_CLK_ENABLE, 12),
116	SG2042_GATE_FW(GATE_CLK_RXU13, "clk_gate_rxu13", "rpgate",
117		       0, R_RP_RXU_CLK_ENABLE, 13),
118	SG2042_GATE_FW(GATE_CLK_RXU14, "clk_gate_rxu14", "rpgate",
119		       0, R_RP_RXU_CLK_ENABLE, 14),
120	SG2042_GATE_FW(GATE_CLK_RXU15, "clk_gate_rxu15", "rpgate",
121		       0, R_RP_RXU_CLK_ENABLE, 15),
122	SG2042_GATE_FW(GATE_CLK_RXU16, "clk_gate_rxu16", "rpgate",
123		       0, R_RP_RXU_CLK_ENABLE, 16),
124	SG2042_GATE_FW(GATE_CLK_RXU17, "clk_gate_rxu17", "rpgate",
125		       0, R_RP_RXU_CLK_ENABLE, 17),
126	SG2042_GATE_FW(GATE_CLK_RXU18, "clk_gate_rxu18", "rpgate",
127		       0, R_RP_RXU_CLK_ENABLE, 18),
128	SG2042_GATE_FW(GATE_CLK_RXU19, "clk_gate_rxu19", "rpgate",
129		       0, R_RP_RXU_CLK_ENABLE, 19),
130	SG2042_GATE_FW(GATE_CLK_RXU20, "clk_gate_rxu20", "rpgate",
131		       0, R_RP_RXU_CLK_ENABLE, 20),
132	SG2042_GATE_FW(GATE_CLK_RXU21, "clk_gate_rxu21", "rpgate",
133		       0, R_RP_RXU_CLK_ENABLE, 21),
134	SG2042_GATE_FW(GATE_CLK_RXU22, "clk_gate_rxu22", "rpgate",
135		       0, R_RP_RXU_CLK_ENABLE, 22),
136	SG2042_GATE_FW(GATE_CLK_RXU23, "clk_gate_rxu23", "rpgate",
137		       0, R_RP_RXU_CLK_ENABLE, 23),
138	SG2042_GATE_FW(GATE_CLK_RXU24, "clk_gate_rxu24", "rpgate",
139		       0, R_RP_RXU_CLK_ENABLE, 24),
140	SG2042_GATE_FW(GATE_CLK_RXU25, "clk_gate_rxu25", "rpgate",
141		       0, R_RP_RXU_CLK_ENABLE, 25),
142	SG2042_GATE_FW(GATE_CLK_RXU26, "clk_gate_rxu26", "rpgate",
143		       0, R_RP_RXU_CLK_ENABLE, 26),
144	SG2042_GATE_FW(GATE_CLK_RXU27, "clk_gate_rxu27", "rpgate",
145		       0, R_RP_RXU_CLK_ENABLE, 27),
146	SG2042_GATE_FW(GATE_CLK_RXU28, "clk_gate_rxu28", "rpgate",
147		       0, R_RP_RXU_CLK_ENABLE, 28),
148	SG2042_GATE_FW(GATE_CLK_RXU29, "clk_gate_rxu29", "rpgate",
149		       0, R_RP_RXU_CLK_ENABLE, 29),
150	SG2042_GATE_FW(GATE_CLK_RXU30, "clk_gate_rxu30", "rpgate",
151		       0, R_RP_RXU_CLK_ENABLE, 30),
152	SG2042_GATE_FW(GATE_CLK_RXU31, "clk_gate_rxu31", "rpgate",
153		       0, R_RP_RXU_CLK_ENABLE, 31),
154
155	/* downstream of clk_gate_rp_cpu_normal about mp */
156	SG2042_GATE_FW(GATE_CLK_MP0, "clk_gate_mp0", "rpgate",
157		       CLK_IS_CRITICAL, R_MP0_CONTROL_REG, 0),
158	SG2042_GATE_FW(GATE_CLK_MP1, "clk_gate_mp1", "rpgate",
159		       CLK_IS_CRITICAL, R_MP1_CONTROL_REG, 0),
160	SG2042_GATE_FW(GATE_CLK_MP2, "clk_gate_mp2", "rpgate",
161		       CLK_IS_CRITICAL, R_MP2_CONTROL_REG, 0),
162	SG2042_GATE_FW(GATE_CLK_MP3, "clk_gate_mp3", "rpgate",
163		       CLK_IS_CRITICAL, R_MP3_CONTROL_REG, 0),
164	SG2042_GATE_FW(GATE_CLK_MP4, "clk_gate_mp4", "rpgate",
165		       CLK_IS_CRITICAL, R_MP4_CONTROL_REG, 0),
166	SG2042_GATE_FW(GATE_CLK_MP5, "clk_gate_mp5", "rpgate",
167		       CLK_IS_CRITICAL, R_MP5_CONTROL_REG, 0),
168	SG2042_GATE_FW(GATE_CLK_MP6, "clk_gate_mp6", "rpgate",
169		       CLK_IS_CRITICAL, R_MP6_CONTROL_REG, 0),
170	SG2042_GATE_FW(GATE_CLK_MP7, "clk_gate_mp7", "rpgate",
171		       CLK_IS_CRITICAL, R_MP7_CONTROL_REG, 0),
172	SG2042_GATE_FW(GATE_CLK_MP8, "clk_gate_mp8", "rpgate",
173		       CLK_IS_CRITICAL, R_MP8_CONTROL_REG, 0),
174	SG2042_GATE_FW(GATE_CLK_MP9, "clk_gate_mp9", "rpgate",
175		       CLK_IS_CRITICAL, R_MP9_CONTROL_REG, 0),
176	SG2042_GATE_FW(GATE_CLK_MP10, "clk_gate_mp10", "rpgate",
177		       CLK_IS_CRITICAL, R_MP10_CONTROL_REG, 0),
178	SG2042_GATE_FW(GATE_CLK_MP11, "clk_gate_mp11", "rpgate",
179		       CLK_IS_CRITICAL, R_MP11_CONTROL_REG, 0),
180	SG2042_GATE_FW(GATE_CLK_MP12, "clk_gate_mp12", "rpgate",
181		       CLK_IS_CRITICAL, R_MP12_CONTROL_REG, 0),
182	SG2042_GATE_FW(GATE_CLK_MP13, "clk_gate_mp13", "rpgate",
183		       CLK_IS_CRITICAL, R_MP13_CONTROL_REG, 0),
184	SG2042_GATE_FW(GATE_CLK_MP14, "clk_gate_mp14", "rpgate",
185		       CLK_IS_CRITICAL, R_MP14_CONTROL_REG, 0),
186	SG2042_GATE_FW(GATE_CLK_MP15, "clk_gate_mp15", "rpgate",
187		       CLK_IS_CRITICAL, R_MP15_CONTROL_REG, 0),
188};
189
190static DEFINE_SPINLOCK(sg2042_clk_lock);
191
192static int sg2042_clk_register_rpgates(struct device *dev,
193				       struct sg2042_clk_data *clk_data,
194				       const struct sg2042_rpgate_clock gate_clks[],
195				       int num_gate_clks)
196{
197	const struct sg2042_rpgate_clock *gate;
198	struct clk_hw *hw;
199	int i, ret = 0;
200
201	for (i = 0; i < num_gate_clks; i++) {
202		gate = &gate_clks[i];
203		hw = devm_clk_hw_register_gate_parent_data
204			(dev,
205			 gate->hw.init->name,
206			 gate->hw.init->parent_data,
207			 gate->hw.init->flags,
208			 clk_data->iobase + gate->offset_enable,
209			 gate->bit_idx,
210			 0,
211			 &sg2042_clk_lock);
212		if (IS_ERR(hw)) {
213			pr_err("failed to register clock %s\n", gate->hw.init->name);
214			ret = PTR_ERR(hw);
215			break;
216		}
217
218		clk_data->onecell_data.hws[gate->id] = hw;
219	}
220
221	return ret;
222}
223
224static int sg2042_init_clkdata(struct platform_device *pdev,
225			       int num_clks,
226			       struct sg2042_clk_data **pp_clk_data)
227{
228	struct sg2042_clk_data *clk_data;
229
230	clk_data = devm_kzalloc(&pdev->dev,
231				struct_size(clk_data, onecell_data.hws, num_clks),
232				GFP_KERNEL);
233	if (!clk_data)
234		return -ENOMEM;
235
236	clk_data->iobase = devm_platform_ioremap_resource(pdev, 0);
237	if (WARN_ON(IS_ERR(clk_data->iobase)))
238		return PTR_ERR(clk_data->iobase);
239
240	clk_data->onecell_data.num = num_clks;
241
242	*pp_clk_data = clk_data;
243
244	return 0;
245}
246
247static int sg2042_rpgate_probe(struct platform_device *pdev)
248{
249	struct sg2042_clk_data *clk_data = NULL;
250	int num_clks;
251	int ret;
252
253	num_clks = ARRAY_SIZE(sg2042_gate_rp);
254
255	ret = sg2042_init_clkdata(pdev, num_clks, &clk_data);
256	if (ret)
257		goto error_out;
258
259	ret = sg2042_clk_register_rpgates(&pdev->dev, clk_data, sg2042_gate_rp,
260					  num_clks);
261	if (ret)
262		goto error_out;
263
264	return devm_of_clk_add_hw_provider(&pdev->dev,
265					   of_clk_hw_onecell_get,
266					   &clk_data->onecell_data);
267
268error_out:
269	pr_err("%s failed error number %d\n", __func__, ret);
270	return ret;
271}
272
273static const struct of_device_id sg2042_rpgate_match[] = {
274	{ .compatible = "sophgo,sg2042-rpgate" },
275	{ /* sentinel */ }
276};
277MODULE_DEVICE_TABLE(of, sg2042_rpgate_match);
278
279static struct platform_driver sg2042_rpgate_driver = {
280	.probe = sg2042_rpgate_probe,
281	.driver = {
282		.name = "clk-sophgo-sg2042-rpgate",
283		.of_match_table = sg2042_rpgate_match,
284		.suppress_bind_attrs = true,
285	},
286};
287module_platform_driver(sg2042_rpgate_driver);
288
289MODULE_AUTHOR("Chen Wang");
290MODULE_DESCRIPTION("Sophgo SG2042 rp subsystem clock driver");
291MODULE_LICENSE("GPL");
~/ Read-only file preview.