xref: /OK3568_Linux_fs/kernel/drivers/clk/tegra/clk-bpmp.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2016 NVIDIA Corporation
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <linux/clk-provider.h>
7*4882a593Smuzhiyun #include <linux/device.h>
8*4882a593Smuzhiyun #include <linux/seq_buf.h>
9*4882a593Smuzhiyun #include <linux/slab.h>
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <soc/tegra/bpmp.h>
12*4882a593Smuzhiyun #include <soc/tegra/bpmp-abi.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #define TEGRA_BPMP_DUMP_CLOCK_INFO	0
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define TEGRA_BPMP_CLK_HAS_MUX		BIT(0)
17*4882a593Smuzhiyun #define TEGRA_BPMP_CLK_HAS_SET_RATE	BIT(1)
18*4882a593Smuzhiyun #define TEGRA_BPMP_CLK_IS_ROOT		BIT(2)
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun struct tegra_bpmp_clk_info {
21*4882a593Smuzhiyun 	unsigned int id;
22*4882a593Smuzhiyun 	char name[MRQ_CLK_NAME_MAXLEN];
23*4882a593Smuzhiyun 	unsigned int parents[MRQ_CLK_MAX_PARENTS];
24*4882a593Smuzhiyun 	unsigned int num_parents;
25*4882a593Smuzhiyun 	unsigned long flags;
26*4882a593Smuzhiyun };
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun struct tegra_bpmp_clk {
29*4882a593Smuzhiyun 	struct clk_hw hw;
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun 	struct tegra_bpmp *bpmp;
32*4882a593Smuzhiyun 	unsigned int id;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	unsigned int num_parents;
35*4882a593Smuzhiyun 	unsigned int *parents;
36*4882a593Smuzhiyun };
37*4882a593Smuzhiyun 
to_tegra_bpmp_clk(struct clk_hw * hw)38*4882a593Smuzhiyun static inline struct tegra_bpmp_clk *to_tegra_bpmp_clk(struct clk_hw *hw)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	return container_of(hw, struct tegra_bpmp_clk, hw);
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun struct tegra_bpmp_clk_message {
44*4882a593Smuzhiyun 	unsigned int cmd;
45*4882a593Smuzhiyun 	unsigned int id;
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	struct {
48*4882a593Smuzhiyun 		const void *data;
49*4882a593Smuzhiyun 		size_t size;
50*4882a593Smuzhiyun 	} tx;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	struct {
53*4882a593Smuzhiyun 		void *data;
54*4882a593Smuzhiyun 		size_t size;
55*4882a593Smuzhiyun 		int ret;
56*4882a593Smuzhiyun 	} rx;
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun 
tegra_bpmp_clk_transfer(struct tegra_bpmp * bpmp,const struct tegra_bpmp_clk_message * clk)59*4882a593Smuzhiyun static int tegra_bpmp_clk_transfer(struct tegra_bpmp *bpmp,
60*4882a593Smuzhiyun 				   const struct tegra_bpmp_clk_message *clk)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	struct mrq_clk_request request;
63*4882a593Smuzhiyun 	struct tegra_bpmp_message msg;
64*4882a593Smuzhiyun 	void *req = &request;
65*4882a593Smuzhiyun 	int err;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	memset(&request, 0, sizeof(request));
68*4882a593Smuzhiyun 	request.cmd_and_id = (clk->cmd << 24) | clk->id;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	/*
71*4882a593Smuzhiyun 	 * The mrq_clk_request structure has an anonymous union at offset 4
72*4882a593Smuzhiyun 	 * that contains all possible sub-command structures. Copy the data
73*4882a593Smuzhiyun 	 * to that union. Ideally we'd be able to refer to it by name, but
74*4882a593Smuzhiyun 	 * doing so would require changing the ABI header and increase the
75*4882a593Smuzhiyun 	 * maintenance burden.
76*4882a593Smuzhiyun 	 */
77*4882a593Smuzhiyun 	memcpy(req + 4, clk->tx.data, clk->tx.size);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
80*4882a593Smuzhiyun 	msg.mrq = MRQ_CLK;
81*4882a593Smuzhiyun 	msg.tx.data = &request;
82*4882a593Smuzhiyun 	msg.tx.size = sizeof(request);
83*4882a593Smuzhiyun 	msg.rx.data = clk->rx.data;
84*4882a593Smuzhiyun 	msg.rx.size = clk->rx.size;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	err = tegra_bpmp_transfer(bpmp, &msg);
87*4882a593Smuzhiyun 	if (err < 0)
88*4882a593Smuzhiyun 		return err;
89*4882a593Smuzhiyun 	else if (msg.rx.ret < 0)
90*4882a593Smuzhiyun 		return -EINVAL;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	return 0;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun 
tegra_bpmp_clk_prepare(struct clk_hw * hw)95*4882a593Smuzhiyun static int tegra_bpmp_clk_prepare(struct clk_hw *hw)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
98*4882a593Smuzhiyun 	struct tegra_bpmp_clk_message msg;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
101*4882a593Smuzhiyun 	msg.cmd = CMD_CLK_ENABLE;
102*4882a593Smuzhiyun 	msg.id = clk->id;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	return tegra_bpmp_clk_transfer(clk->bpmp, &msg);
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun 
tegra_bpmp_clk_unprepare(struct clk_hw * hw)107*4882a593Smuzhiyun static void tegra_bpmp_clk_unprepare(struct clk_hw *hw)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
110*4882a593Smuzhiyun 	struct tegra_bpmp_clk_message msg;
111*4882a593Smuzhiyun 	int err;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
114*4882a593Smuzhiyun 	msg.cmd = CMD_CLK_DISABLE;
115*4882a593Smuzhiyun 	msg.id = clk->id;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
118*4882a593Smuzhiyun 	if (err < 0)
119*4882a593Smuzhiyun 		dev_err(clk->bpmp->dev, "failed to disable clock %s: %d\n",
120*4882a593Smuzhiyun 			clk_hw_get_name(hw), err);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
tegra_bpmp_clk_is_prepared(struct clk_hw * hw)123*4882a593Smuzhiyun static int tegra_bpmp_clk_is_prepared(struct clk_hw *hw)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
126*4882a593Smuzhiyun 	struct cmd_clk_is_enabled_response response;
127*4882a593Smuzhiyun 	struct tegra_bpmp_clk_message msg;
128*4882a593Smuzhiyun 	int err;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
131*4882a593Smuzhiyun 	msg.cmd = CMD_CLK_IS_ENABLED;
132*4882a593Smuzhiyun 	msg.id = clk->id;
133*4882a593Smuzhiyun 	msg.rx.data = &response;
134*4882a593Smuzhiyun 	msg.rx.size = sizeof(response);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
137*4882a593Smuzhiyun 	if (err < 0)
138*4882a593Smuzhiyun 		return err;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	return response.state;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun 
tegra_bpmp_clk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)143*4882a593Smuzhiyun static unsigned long tegra_bpmp_clk_recalc_rate(struct clk_hw *hw,
144*4882a593Smuzhiyun 						unsigned long parent_rate)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
147*4882a593Smuzhiyun 	struct cmd_clk_get_rate_response response;
148*4882a593Smuzhiyun 	struct cmd_clk_get_rate_request request;
149*4882a593Smuzhiyun 	struct tegra_bpmp_clk_message msg;
150*4882a593Smuzhiyun 	int err;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
153*4882a593Smuzhiyun 	msg.cmd = CMD_CLK_GET_RATE;
154*4882a593Smuzhiyun 	msg.id = clk->id;
155*4882a593Smuzhiyun 	msg.tx.data = &request;
156*4882a593Smuzhiyun 	msg.tx.size = sizeof(request);
157*4882a593Smuzhiyun 	msg.rx.data = &response;
158*4882a593Smuzhiyun 	msg.rx.size = sizeof(response);
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
161*4882a593Smuzhiyun 	if (err < 0)
162*4882a593Smuzhiyun 		return err;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	return response.rate;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
tegra_bpmp_clk_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)167*4882a593Smuzhiyun static long tegra_bpmp_clk_round_rate(struct clk_hw *hw, unsigned long rate,
168*4882a593Smuzhiyun 				      unsigned long *parent_rate)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun 	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
171*4882a593Smuzhiyun 	struct cmd_clk_round_rate_response response;
172*4882a593Smuzhiyun 	struct cmd_clk_round_rate_request request;
173*4882a593Smuzhiyun 	struct tegra_bpmp_clk_message msg;
174*4882a593Smuzhiyun 	int err;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	memset(&request, 0, sizeof(request));
177*4882a593Smuzhiyun 	request.rate = rate;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
180*4882a593Smuzhiyun 	msg.cmd = CMD_CLK_ROUND_RATE;
181*4882a593Smuzhiyun 	msg.id = clk->id;
182*4882a593Smuzhiyun 	msg.tx.data = &request;
183*4882a593Smuzhiyun 	msg.tx.size = sizeof(request);
184*4882a593Smuzhiyun 	msg.rx.data = &response;
185*4882a593Smuzhiyun 	msg.rx.size = sizeof(response);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
188*4882a593Smuzhiyun 	if (err < 0)
189*4882a593Smuzhiyun 		return err;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	return response.rate;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun 
tegra_bpmp_clk_set_parent(struct clk_hw * hw,u8 index)194*4882a593Smuzhiyun static int tegra_bpmp_clk_set_parent(struct clk_hw *hw, u8 index)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun 	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
197*4882a593Smuzhiyun 	struct cmd_clk_set_parent_response response;
198*4882a593Smuzhiyun 	struct cmd_clk_set_parent_request request;
199*4882a593Smuzhiyun 	struct tegra_bpmp_clk_message msg;
200*4882a593Smuzhiyun 	int err;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	memset(&request, 0, sizeof(request));
203*4882a593Smuzhiyun 	request.parent_id = clk->parents[index];
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
206*4882a593Smuzhiyun 	msg.cmd = CMD_CLK_SET_PARENT;
207*4882a593Smuzhiyun 	msg.id = clk->id;
208*4882a593Smuzhiyun 	msg.tx.data = &request;
209*4882a593Smuzhiyun 	msg.tx.size = sizeof(request);
210*4882a593Smuzhiyun 	msg.rx.data = &response;
211*4882a593Smuzhiyun 	msg.rx.size = sizeof(response);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
214*4882a593Smuzhiyun 	if (err < 0)
215*4882a593Smuzhiyun 		return err;
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	/* XXX check parent ID in response */
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	return 0;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
tegra_bpmp_clk_get_parent(struct clk_hw * hw)222*4882a593Smuzhiyun static u8 tegra_bpmp_clk_get_parent(struct clk_hw *hw)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
225*4882a593Smuzhiyun 	struct cmd_clk_get_parent_response response;
226*4882a593Smuzhiyun 	struct tegra_bpmp_clk_message msg;
227*4882a593Smuzhiyun 	unsigned int i;
228*4882a593Smuzhiyun 	int err;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
231*4882a593Smuzhiyun 	msg.cmd = CMD_CLK_GET_PARENT;
232*4882a593Smuzhiyun 	msg.id = clk->id;
233*4882a593Smuzhiyun 	msg.rx.data = &response;
234*4882a593Smuzhiyun 	msg.rx.size = sizeof(response);
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
237*4882a593Smuzhiyun 	if (err < 0) {
238*4882a593Smuzhiyun 		dev_err(clk->bpmp->dev, "failed to get parent for %s: %d\n",
239*4882a593Smuzhiyun 			clk_hw_get_name(hw), err);
240*4882a593Smuzhiyun 		return U8_MAX;
241*4882a593Smuzhiyun 	}
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	for (i = 0; i < clk->num_parents; i++)
244*4882a593Smuzhiyun 		if (clk->parents[i] == response.parent_id)
245*4882a593Smuzhiyun 			return i;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	return U8_MAX;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun 
tegra_bpmp_clk_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)250*4882a593Smuzhiyun static int tegra_bpmp_clk_set_rate(struct clk_hw *hw, unsigned long rate,
251*4882a593Smuzhiyun 				   unsigned long parent_rate)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun 	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
254*4882a593Smuzhiyun 	struct cmd_clk_set_rate_response response;
255*4882a593Smuzhiyun 	struct cmd_clk_set_rate_request request;
256*4882a593Smuzhiyun 	struct tegra_bpmp_clk_message msg;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	memset(&request, 0, sizeof(request));
259*4882a593Smuzhiyun 	request.rate = rate;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
262*4882a593Smuzhiyun 	msg.cmd = CMD_CLK_SET_RATE;
263*4882a593Smuzhiyun 	msg.id = clk->id;
264*4882a593Smuzhiyun 	msg.tx.data = &request;
265*4882a593Smuzhiyun 	msg.tx.size = sizeof(request);
266*4882a593Smuzhiyun 	msg.rx.data = &response;
267*4882a593Smuzhiyun 	msg.rx.size = sizeof(response);
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	return tegra_bpmp_clk_transfer(clk->bpmp, &msg);
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun static const struct clk_ops tegra_bpmp_clk_gate_ops = {
273*4882a593Smuzhiyun 	.prepare = tegra_bpmp_clk_prepare,
274*4882a593Smuzhiyun 	.unprepare = tegra_bpmp_clk_unprepare,
275*4882a593Smuzhiyun 	.is_prepared = tegra_bpmp_clk_is_prepared,
276*4882a593Smuzhiyun 	.recalc_rate = tegra_bpmp_clk_recalc_rate,
277*4882a593Smuzhiyun };
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun static const struct clk_ops tegra_bpmp_clk_mux_ops = {
280*4882a593Smuzhiyun 	.prepare = tegra_bpmp_clk_prepare,
281*4882a593Smuzhiyun 	.unprepare = tegra_bpmp_clk_unprepare,
282*4882a593Smuzhiyun 	.is_prepared = tegra_bpmp_clk_is_prepared,
283*4882a593Smuzhiyun 	.recalc_rate = tegra_bpmp_clk_recalc_rate,
284*4882a593Smuzhiyun 	.set_parent = tegra_bpmp_clk_set_parent,
285*4882a593Smuzhiyun 	.get_parent = tegra_bpmp_clk_get_parent,
286*4882a593Smuzhiyun };
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun static const struct clk_ops tegra_bpmp_clk_rate_ops = {
289*4882a593Smuzhiyun 	.prepare = tegra_bpmp_clk_prepare,
290*4882a593Smuzhiyun 	.unprepare = tegra_bpmp_clk_unprepare,
291*4882a593Smuzhiyun 	.is_prepared = tegra_bpmp_clk_is_prepared,
292*4882a593Smuzhiyun 	.recalc_rate = tegra_bpmp_clk_recalc_rate,
293*4882a593Smuzhiyun 	.round_rate = tegra_bpmp_clk_round_rate,
294*4882a593Smuzhiyun 	.set_rate = tegra_bpmp_clk_set_rate,
295*4882a593Smuzhiyun };
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun static const struct clk_ops tegra_bpmp_clk_mux_rate_ops = {
298*4882a593Smuzhiyun 	.prepare = tegra_bpmp_clk_prepare,
299*4882a593Smuzhiyun 	.unprepare = tegra_bpmp_clk_unprepare,
300*4882a593Smuzhiyun 	.is_prepared = tegra_bpmp_clk_is_prepared,
301*4882a593Smuzhiyun 	.recalc_rate = tegra_bpmp_clk_recalc_rate,
302*4882a593Smuzhiyun 	.round_rate = tegra_bpmp_clk_round_rate,
303*4882a593Smuzhiyun 	.set_parent = tegra_bpmp_clk_set_parent,
304*4882a593Smuzhiyun 	.get_parent = tegra_bpmp_clk_get_parent,
305*4882a593Smuzhiyun 	.set_rate = tegra_bpmp_clk_set_rate,
306*4882a593Smuzhiyun };
307*4882a593Smuzhiyun 
tegra_bpmp_clk_get_max_id(struct tegra_bpmp * bpmp)308*4882a593Smuzhiyun static int tegra_bpmp_clk_get_max_id(struct tegra_bpmp *bpmp)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun 	struct cmd_clk_get_max_clk_id_response response;
311*4882a593Smuzhiyun 	struct tegra_bpmp_clk_message msg;
312*4882a593Smuzhiyun 	int err;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
315*4882a593Smuzhiyun 	msg.cmd = CMD_CLK_GET_MAX_CLK_ID;
316*4882a593Smuzhiyun 	msg.rx.data = &response;
317*4882a593Smuzhiyun 	msg.rx.size = sizeof(response);
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	err = tegra_bpmp_clk_transfer(bpmp, &msg);
320*4882a593Smuzhiyun 	if (err < 0)
321*4882a593Smuzhiyun 		return err;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	if (response.max_id > INT_MAX)
324*4882a593Smuzhiyun 		return -E2BIG;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	return response.max_id;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
tegra_bpmp_clk_get_info(struct tegra_bpmp * bpmp,unsigned int id,struct tegra_bpmp_clk_info * info)329*4882a593Smuzhiyun static int tegra_bpmp_clk_get_info(struct tegra_bpmp *bpmp, unsigned int id,
330*4882a593Smuzhiyun 				   struct tegra_bpmp_clk_info *info)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun 	struct cmd_clk_get_all_info_response response;
333*4882a593Smuzhiyun 	struct tegra_bpmp_clk_message msg;
334*4882a593Smuzhiyun 	unsigned int i;
335*4882a593Smuzhiyun 	int err;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
338*4882a593Smuzhiyun 	msg.cmd = CMD_CLK_GET_ALL_INFO;
339*4882a593Smuzhiyun 	msg.id = id;
340*4882a593Smuzhiyun 	msg.rx.data = &response;
341*4882a593Smuzhiyun 	msg.rx.size = sizeof(response);
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	err = tegra_bpmp_clk_transfer(bpmp, &msg);
344*4882a593Smuzhiyun 	if (err < 0)
345*4882a593Smuzhiyun 		return err;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	strlcpy(info->name, response.name, MRQ_CLK_NAME_MAXLEN);
348*4882a593Smuzhiyun 	info->num_parents = response.num_parents;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	for (i = 0; i < info->num_parents; i++)
351*4882a593Smuzhiyun 		info->parents[i] = response.parents[i];
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	info->flags = response.flags;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	return 0;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun 
tegra_bpmp_clk_info_dump(struct tegra_bpmp * bpmp,const char * level,const struct tegra_bpmp_clk_info * info)358*4882a593Smuzhiyun static void tegra_bpmp_clk_info_dump(struct tegra_bpmp *bpmp,
359*4882a593Smuzhiyun 				     const char *level,
360*4882a593Smuzhiyun 				     const struct tegra_bpmp_clk_info *info)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun 	const char *prefix = "";
363*4882a593Smuzhiyun 	struct seq_buf buf;
364*4882a593Smuzhiyun 	unsigned int i;
365*4882a593Smuzhiyun 	char flags[64];
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	seq_buf_init(&buf, flags, sizeof(flags));
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	if (info->flags)
370*4882a593Smuzhiyun 		seq_buf_printf(&buf, "(");
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	if (info->flags & TEGRA_BPMP_CLK_HAS_MUX) {
373*4882a593Smuzhiyun 		seq_buf_printf(&buf, "%smux", prefix);
374*4882a593Smuzhiyun 		prefix = ", ";
375*4882a593Smuzhiyun 	}
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	if ((info->flags & TEGRA_BPMP_CLK_HAS_SET_RATE) == 0) {
378*4882a593Smuzhiyun 		seq_buf_printf(&buf, "%sfixed", prefix);
379*4882a593Smuzhiyun 		prefix = ", ";
380*4882a593Smuzhiyun 	}
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	if (info->flags & TEGRA_BPMP_CLK_IS_ROOT) {
383*4882a593Smuzhiyun 		seq_buf_printf(&buf, "%sroot", prefix);
384*4882a593Smuzhiyun 		prefix = ", ";
385*4882a593Smuzhiyun 	}
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	if (info->flags)
388*4882a593Smuzhiyun 		seq_buf_printf(&buf, ")");
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	dev_printk(level, bpmp->dev, "%03u: %s\n", info->id, info->name);
391*4882a593Smuzhiyun 	dev_printk(level, bpmp->dev, "  flags: %lx %s\n", info->flags, flags);
392*4882a593Smuzhiyun 	dev_printk(level, bpmp->dev, "  parents: %u\n", info->num_parents);
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	for (i = 0; i < info->num_parents; i++)
395*4882a593Smuzhiyun 		dev_printk(level, bpmp->dev, "    %03u\n", info->parents[i]);
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun 
tegra_bpmp_probe_clocks(struct tegra_bpmp * bpmp,struct tegra_bpmp_clk_info ** clocksp)398*4882a593Smuzhiyun static int tegra_bpmp_probe_clocks(struct tegra_bpmp *bpmp,
399*4882a593Smuzhiyun 				   struct tegra_bpmp_clk_info **clocksp)
400*4882a593Smuzhiyun {
401*4882a593Smuzhiyun 	struct tegra_bpmp_clk_info *clocks;
402*4882a593Smuzhiyun 	unsigned int max_id, id, count = 0;
403*4882a593Smuzhiyun 	unsigned int holes = 0;
404*4882a593Smuzhiyun 	int err;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	err = tegra_bpmp_clk_get_max_id(bpmp);
407*4882a593Smuzhiyun 	if (err < 0)
408*4882a593Smuzhiyun 		return err;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	max_id = err;
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	dev_dbg(bpmp->dev, "maximum clock ID: %u\n", max_id);
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	clocks = kcalloc(max_id + 1, sizeof(*clocks), GFP_KERNEL);
415*4882a593Smuzhiyun 	if (!clocks)
416*4882a593Smuzhiyun 		return -ENOMEM;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	for (id = 0; id <= max_id; id++) {
419*4882a593Smuzhiyun 		struct tegra_bpmp_clk_info *info = &clocks[count];
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 		err = tegra_bpmp_clk_get_info(bpmp, id, info);
422*4882a593Smuzhiyun 		if (err < 0)
423*4882a593Smuzhiyun 			continue;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 		if (info->num_parents >= U8_MAX) {
426*4882a593Smuzhiyun 			dev_err(bpmp->dev,
427*4882a593Smuzhiyun 				"clock %u has too many parents (%u, max: %u)\n",
428*4882a593Smuzhiyun 				id, info->num_parents, U8_MAX);
429*4882a593Smuzhiyun 			continue;
430*4882a593Smuzhiyun 		}
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 		/* clock not exposed by BPMP */
433*4882a593Smuzhiyun 		if (info->name[0] == '\0') {
434*4882a593Smuzhiyun 			holes++;
435*4882a593Smuzhiyun 			continue;
436*4882a593Smuzhiyun 		}
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 		info->id = id;
439*4882a593Smuzhiyun 		count++;
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 		if (TEGRA_BPMP_DUMP_CLOCK_INFO)
442*4882a593Smuzhiyun 			tegra_bpmp_clk_info_dump(bpmp, KERN_DEBUG, info);
443*4882a593Smuzhiyun 	}
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	dev_dbg(bpmp->dev, "holes: %u\n", holes);
446*4882a593Smuzhiyun 	*clocksp = clocks;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	return count;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun static const struct tegra_bpmp_clk_info *
tegra_bpmp_clk_find(const struct tegra_bpmp_clk_info * clocks,unsigned int num_clocks,unsigned int id)452*4882a593Smuzhiyun tegra_bpmp_clk_find(const struct tegra_bpmp_clk_info *clocks,
453*4882a593Smuzhiyun 		    unsigned int num_clocks, unsigned int id)
454*4882a593Smuzhiyun {
455*4882a593Smuzhiyun 	unsigned int i;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	for (i = 0; i < num_clocks; i++)
458*4882a593Smuzhiyun 		if (clocks[i].id == id)
459*4882a593Smuzhiyun 			return &clocks[i];
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	return NULL;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun static struct tegra_bpmp_clk *
tegra_bpmp_clk_register(struct tegra_bpmp * bpmp,const struct tegra_bpmp_clk_info * info,const struct tegra_bpmp_clk_info * clocks,unsigned int num_clocks)465*4882a593Smuzhiyun tegra_bpmp_clk_register(struct tegra_bpmp *bpmp,
466*4882a593Smuzhiyun 			const struct tegra_bpmp_clk_info *info,
467*4882a593Smuzhiyun 			const struct tegra_bpmp_clk_info *clocks,
468*4882a593Smuzhiyun 			unsigned int num_clocks)
469*4882a593Smuzhiyun {
470*4882a593Smuzhiyun 	struct tegra_bpmp_clk *clk;
471*4882a593Smuzhiyun 	struct clk_init_data init;
472*4882a593Smuzhiyun 	const char **parents;
473*4882a593Smuzhiyun 	unsigned int i;
474*4882a593Smuzhiyun 	int err;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	clk = devm_kzalloc(bpmp->dev, sizeof(*clk), GFP_KERNEL);
477*4882a593Smuzhiyun 	if (!clk)
478*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	clk->id = info->id;
481*4882a593Smuzhiyun 	clk->bpmp = bpmp;
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	clk->parents = devm_kcalloc(bpmp->dev, info->num_parents,
484*4882a593Smuzhiyun 				    sizeof(*clk->parents), GFP_KERNEL);
485*4882a593Smuzhiyun 	if (!clk->parents)
486*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	clk->num_parents = info->num_parents;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	/* hardware clock initialization */
491*4882a593Smuzhiyun 	memset(&init, 0, sizeof(init));
492*4882a593Smuzhiyun 	init.name = info->name;
493*4882a593Smuzhiyun 	clk->hw.init = &init;
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	if (info->flags & TEGRA_BPMP_CLK_HAS_MUX) {
496*4882a593Smuzhiyun 		if (info->flags & TEGRA_BPMP_CLK_HAS_SET_RATE)
497*4882a593Smuzhiyun 			init.ops = &tegra_bpmp_clk_mux_rate_ops;
498*4882a593Smuzhiyun 		else
499*4882a593Smuzhiyun 			init.ops = &tegra_bpmp_clk_mux_ops;
500*4882a593Smuzhiyun 	} else {
501*4882a593Smuzhiyun 		if (info->flags & TEGRA_BPMP_CLK_HAS_SET_RATE)
502*4882a593Smuzhiyun 			init.ops = &tegra_bpmp_clk_rate_ops;
503*4882a593Smuzhiyun 		else
504*4882a593Smuzhiyun 			init.ops = &tegra_bpmp_clk_gate_ops;
505*4882a593Smuzhiyun 	}
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	init.num_parents = info->num_parents;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	parents = kcalloc(info->num_parents, sizeof(*parents), GFP_KERNEL);
510*4882a593Smuzhiyun 	if (!parents)
511*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	for (i = 0; i < info->num_parents; i++) {
514*4882a593Smuzhiyun 		const struct tegra_bpmp_clk_info *parent;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 		/* keep a private copy of the ID to parent index map */
517*4882a593Smuzhiyun 		clk->parents[i] = info->parents[i];
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 		parent = tegra_bpmp_clk_find(clocks, num_clocks,
520*4882a593Smuzhiyun 					     info->parents[i]);
521*4882a593Smuzhiyun 		if (!parent) {
522*4882a593Smuzhiyun 			dev_err(bpmp->dev, "no parent %u found for %u\n",
523*4882a593Smuzhiyun 				info->parents[i], info->id);
524*4882a593Smuzhiyun 			continue;
525*4882a593Smuzhiyun 		}
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 		parents[i] = parent->name;
528*4882a593Smuzhiyun 	}
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	init.parent_names = parents;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	err = devm_clk_hw_register(bpmp->dev, &clk->hw);
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 	kfree(parents);
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	if (err < 0)
537*4882a593Smuzhiyun 		return ERR_PTR(err);
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	return clk;
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun 
tegra_bpmp_register_clocks(struct tegra_bpmp * bpmp,struct tegra_bpmp_clk_info * infos,unsigned int count)542*4882a593Smuzhiyun static int tegra_bpmp_register_clocks(struct tegra_bpmp *bpmp,
543*4882a593Smuzhiyun 				      struct tegra_bpmp_clk_info *infos,
544*4882a593Smuzhiyun 				      unsigned int count)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun 	struct tegra_bpmp_clk *clk;
547*4882a593Smuzhiyun 	unsigned int i;
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	bpmp->num_clocks = count;
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	bpmp->clocks = devm_kcalloc(bpmp->dev, count, sizeof(clk), GFP_KERNEL);
552*4882a593Smuzhiyun 	if (!bpmp->clocks)
553*4882a593Smuzhiyun 		return -ENOMEM;
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	for (i = 0; i < count; i++) {
556*4882a593Smuzhiyun 		struct tegra_bpmp_clk_info *info = &infos[i];
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 		clk = tegra_bpmp_clk_register(bpmp, info, infos, count);
559*4882a593Smuzhiyun 		if (IS_ERR(clk)) {
560*4882a593Smuzhiyun 			dev_err(bpmp->dev,
561*4882a593Smuzhiyun 				"failed to register clock %u (%s): %ld\n",
562*4882a593Smuzhiyun 				info->id, info->name, PTR_ERR(clk));
563*4882a593Smuzhiyun 			continue;
564*4882a593Smuzhiyun 		}
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 		bpmp->clocks[i] = clk;
567*4882a593Smuzhiyun 	}
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	return 0;
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun 
tegra_bpmp_unregister_clocks(struct tegra_bpmp * bpmp)572*4882a593Smuzhiyun static void tegra_bpmp_unregister_clocks(struct tegra_bpmp *bpmp)
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun 	unsigned int i;
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	for (i = 0; i < bpmp->num_clocks; i++)
577*4882a593Smuzhiyun 		clk_hw_unregister(&bpmp->clocks[i]->hw);
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun 
tegra_bpmp_clk_of_xlate(struct of_phandle_args * clkspec,void * data)580*4882a593Smuzhiyun static struct clk_hw *tegra_bpmp_clk_of_xlate(struct of_phandle_args *clkspec,
581*4882a593Smuzhiyun 					      void *data)
582*4882a593Smuzhiyun {
583*4882a593Smuzhiyun 	unsigned int id = clkspec->args[0], i;
584*4882a593Smuzhiyun 	struct tegra_bpmp *bpmp = data;
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	for (i = 0; i < bpmp->num_clocks; i++) {
587*4882a593Smuzhiyun 		struct tegra_bpmp_clk *clk = bpmp->clocks[i];
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 		if (!clk)
590*4882a593Smuzhiyun 			continue;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 		if (clk->id == id)
593*4882a593Smuzhiyun 			return &clk->hw;
594*4882a593Smuzhiyun 	}
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	return NULL;
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun 
tegra_bpmp_init_clocks(struct tegra_bpmp * bpmp)599*4882a593Smuzhiyun int tegra_bpmp_init_clocks(struct tegra_bpmp *bpmp)
600*4882a593Smuzhiyun {
601*4882a593Smuzhiyun 	struct tegra_bpmp_clk_info *clocks;
602*4882a593Smuzhiyun 	unsigned int count;
603*4882a593Smuzhiyun 	int err;
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	err = tegra_bpmp_probe_clocks(bpmp, &clocks);
606*4882a593Smuzhiyun 	if (err < 0)
607*4882a593Smuzhiyun 		return err;
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	count = err;
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	dev_dbg(bpmp->dev, "%u clocks probed\n", count);
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	err = tegra_bpmp_register_clocks(bpmp, clocks, count);
614*4882a593Smuzhiyun 	if (err < 0)
615*4882a593Smuzhiyun 		goto free;
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	err = of_clk_add_hw_provider(bpmp->dev->of_node,
618*4882a593Smuzhiyun 				     tegra_bpmp_clk_of_xlate,
619*4882a593Smuzhiyun 				     bpmp);
620*4882a593Smuzhiyun 	if (err < 0) {
621*4882a593Smuzhiyun 		tegra_bpmp_unregister_clocks(bpmp);
622*4882a593Smuzhiyun 		goto free;
623*4882a593Smuzhiyun 	}
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun free:
626*4882a593Smuzhiyun 	kfree(clocks);
627*4882a593Smuzhiyun 	return err;
628*4882a593Smuzhiyun }
629