This source file includes following definitions.
- to_clk_scu
- imx_clk_scu_init
- clk_scu_recalc_rate
- clk_scu_round_rate
- clk_scu_atf_set_cpu_rate
- clk_scu_set_rate
- clk_scu_get_parent
- clk_scu_set_parent
- sc_pm_clock_enable
- clk_scu_prepare
- clk_scu_unprepare
- __imx_clk_scu
1
2
3
4
5
6
7 #include <dt-bindings/firmware/imx/rsrc.h>
8 #include <linux/arm-smccc.h>
9 #include <linux/clk-provider.h>
10 #include <linux/err.h>
11 #include <linux/slab.h>
12
13 #include "clk-scu.h"
14
15 #define IMX_SIP_CPUFREQ 0xC2000001
16 #define IMX_SIP_SET_CPUFREQ 0x00
17
18 static struct imx_sc_ipc *ccm_ipc_handle;
19
20
21
22
23
24
25
26 struct clk_scu {
27 struct clk_hw hw;
28 u16 rsrc_id;
29 u8 clk_type;
30 };
31
32
33
34
35
36
37
38
39
40
41 struct imx_sc_msg_req_set_clock_rate {
42 struct imx_sc_rpc_msg hdr;
43 __le32 rate;
44 __le16 resource;
45 u8 clk;
46 } __packed __aligned(4);
47
48 struct req_get_clock_rate {
49 __le16 resource;
50 u8 clk;
51 } __packed __aligned(4);
52
53 struct resp_get_clock_rate {
54 __le32 rate;
55 };
56
57
58
59
60
61
62
63
64
65 struct imx_sc_msg_get_clock_rate {
66 struct imx_sc_rpc_msg hdr;
67 union {
68 struct req_get_clock_rate req;
69 struct resp_get_clock_rate resp;
70 } data;
71 };
72
73
74
75
76
77
78
79
80
81 struct imx_sc_msg_get_clock_parent {
82 struct imx_sc_rpc_msg hdr;
83 union {
84 struct req_get_clock_parent {
85 __le16 resource;
86 u8 clk;
87 } __packed __aligned(4) req;
88 struct resp_get_clock_parent {
89 u8 parent;
90 } resp;
91 } data;
92 };
93
94
95
96
97
98
99
100
101 struct imx_sc_msg_set_clock_parent {
102 struct imx_sc_rpc_msg hdr;
103 __le16 resource;
104 u8 clk;
105 u8 parent;
106 } __packed;
107
108
109
110
111
112
113
114
115
116
117
118 struct imx_sc_msg_req_clock_enable {
119 struct imx_sc_rpc_msg hdr;
120 __le16 resource;
121 u8 clk;
122 u8 enable;
123 u8 autog;
124 } __packed __aligned(4);
125
126 static inline struct clk_scu *to_clk_scu(struct clk_hw *hw)
127 {
128 return container_of(hw, struct clk_scu, hw);
129 }
130
131 int imx_clk_scu_init(void)
132 {
133 return imx_scu_get_handle(&ccm_ipc_handle);
134 }
135
136
137
138
139
140
141
142
143
144 static unsigned long clk_scu_recalc_rate(struct clk_hw *hw,
145 unsigned long parent_rate)
146 {
147 struct clk_scu *clk = to_clk_scu(hw);
148 struct imx_sc_msg_get_clock_rate msg;
149 struct imx_sc_rpc_msg *hdr = &msg.hdr;
150 int ret;
151
152 hdr->ver = IMX_SC_RPC_VERSION;
153 hdr->svc = IMX_SC_RPC_SVC_PM;
154 hdr->func = IMX_SC_PM_FUNC_GET_CLOCK_RATE;
155 hdr->size = 2;
156
157 msg.data.req.resource = cpu_to_le16(clk->rsrc_id);
158 msg.data.req.clk = clk->clk_type;
159
160 ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
161 if (ret) {
162 pr_err("%s: failed to get clock rate %d\n",
163 clk_hw_get_name(hw), ret);
164 return 0;
165 }
166
167 return le32_to_cpu(msg.data.resp.rate);
168 }
169
170
171
172
173
174
175
176
177
178 static long clk_scu_round_rate(struct clk_hw *hw, unsigned long rate,
179 unsigned long *parent_rate)
180 {
181
182
183
184
185 return rate;
186 }
187
188 static int clk_scu_atf_set_cpu_rate(struct clk_hw *hw, unsigned long rate,
189 unsigned long parent_rate)
190 {
191 struct clk_scu *clk = to_clk_scu(hw);
192 struct arm_smccc_res res;
193 unsigned long cluster_id;
194
195 if (clk->rsrc_id == IMX_SC_R_A35)
196 cluster_id = 0;
197 else
198 return -EINVAL;
199
200
201 arm_smccc_smc(IMX_SIP_CPUFREQ, IMX_SIP_SET_CPUFREQ,
202 cluster_id, rate, 0, 0, 0, 0, &res);
203
204 return 0;
205 }
206
207
208
209
210
211
212
213
214
215
216 static int clk_scu_set_rate(struct clk_hw *hw, unsigned long rate,
217 unsigned long parent_rate)
218 {
219 struct clk_scu *clk = to_clk_scu(hw);
220 struct imx_sc_msg_req_set_clock_rate msg;
221 struct imx_sc_rpc_msg *hdr = &msg.hdr;
222
223 hdr->ver = IMX_SC_RPC_VERSION;
224 hdr->svc = IMX_SC_RPC_SVC_PM;
225 hdr->func = IMX_SC_PM_FUNC_SET_CLOCK_RATE;
226 hdr->size = 3;
227
228 msg.rate = cpu_to_le32(rate);
229 msg.resource = cpu_to_le16(clk->rsrc_id);
230 msg.clk = clk->clk_type;
231
232 return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
233 }
234
235 static u8 clk_scu_get_parent(struct clk_hw *hw)
236 {
237 struct clk_scu *clk = to_clk_scu(hw);
238 struct imx_sc_msg_get_clock_parent msg;
239 struct imx_sc_rpc_msg *hdr = &msg.hdr;
240 int ret;
241
242 hdr->ver = IMX_SC_RPC_VERSION;
243 hdr->svc = IMX_SC_RPC_SVC_PM;
244 hdr->func = IMX_SC_PM_FUNC_GET_CLOCK_PARENT;
245 hdr->size = 2;
246
247 msg.data.req.resource = cpu_to_le16(clk->rsrc_id);
248 msg.data.req.clk = clk->clk_type;
249
250 ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
251 if (ret) {
252 pr_err("%s: failed to get clock parent %d\n",
253 clk_hw_get_name(hw), ret);
254 return 0;
255 }
256
257 return msg.data.resp.parent;
258 }
259
260 static int clk_scu_set_parent(struct clk_hw *hw, u8 index)
261 {
262 struct clk_scu *clk = to_clk_scu(hw);
263 struct imx_sc_msg_set_clock_parent msg;
264 struct imx_sc_rpc_msg *hdr = &msg.hdr;
265
266 hdr->ver = IMX_SC_RPC_VERSION;
267 hdr->svc = IMX_SC_RPC_SVC_PM;
268 hdr->func = IMX_SC_PM_FUNC_SET_CLOCK_PARENT;
269 hdr->size = 2;
270
271 msg.resource = cpu_to_le16(clk->rsrc_id);
272 msg.clk = clk->clk_type;
273 msg.parent = index;
274
275 return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
276 }
277
278 static int sc_pm_clock_enable(struct imx_sc_ipc *ipc, u16 resource,
279 u8 clk, bool enable, bool autog)
280 {
281 struct imx_sc_msg_req_clock_enable msg;
282 struct imx_sc_rpc_msg *hdr = &msg.hdr;
283
284 hdr->ver = IMX_SC_RPC_VERSION;
285 hdr->svc = IMX_SC_RPC_SVC_PM;
286 hdr->func = IMX_SC_PM_FUNC_CLOCK_ENABLE;
287 hdr->size = 3;
288
289 msg.resource = cpu_to_le16(resource);
290 msg.clk = clk;
291 msg.enable = enable;
292 msg.autog = autog;
293
294 return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
295 }
296
297
298
299
300
301
302
303 static int clk_scu_prepare(struct clk_hw *hw)
304 {
305 struct clk_scu *clk = to_clk_scu(hw);
306
307 return sc_pm_clock_enable(ccm_ipc_handle, clk->rsrc_id,
308 clk->clk_type, true, false);
309 }
310
311
312
313
314
315
316
317 static void clk_scu_unprepare(struct clk_hw *hw)
318 {
319 struct clk_scu *clk = to_clk_scu(hw);
320 int ret;
321
322 ret = sc_pm_clock_enable(ccm_ipc_handle, clk->rsrc_id,
323 clk->clk_type, false, false);
324 if (ret)
325 pr_warn("%s: clk unprepare failed %d\n", clk_hw_get_name(hw),
326 ret);
327 }
328
329 static const struct clk_ops clk_scu_ops = {
330 .recalc_rate = clk_scu_recalc_rate,
331 .round_rate = clk_scu_round_rate,
332 .set_rate = clk_scu_set_rate,
333 .get_parent = clk_scu_get_parent,
334 .set_parent = clk_scu_set_parent,
335 .prepare = clk_scu_prepare,
336 .unprepare = clk_scu_unprepare,
337 };
338
339 static const struct clk_ops clk_scu_cpu_ops = {
340 .recalc_rate = clk_scu_recalc_rate,
341 .round_rate = clk_scu_round_rate,
342 .set_rate = clk_scu_atf_set_cpu_rate,
343 .prepare = clk_scu_prepare,
344 .unprepare = clk_scu_unprepare,
345 };
346
347 struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
348 int num_parents, u32 rsrc_id, u8 clk_type)
349 {
350 struct clk_init_data init;
351 struct clk_scu *clk;
352 struct clk_hw *hw;
353 int ret;
354
355 clk = kzalloc(sizeof(*clk), GFP_KERNEL);
356 if (!clk)
357 return ERR_PTR(-ENOMEM);
358
359 clk->rsrc_id = rsrc_id;
360 clk->clk_type = clk_type;
361
362 init.name = name;
363 init.ops = &clk_scu_ops;
364 if (rsrc_id == IMX_SC_R_A35)
365 init.ops = &clk_scu_cpu_ops;
366 else
367 init.ops = &clk_scu_ops;
368 init.parent_names = parents;
369 init.num_parents = num_parents;
370
371
372
373
374
375
376
377
378 init.flags = CLK_GET_RATE_NOCACHE;
379 clk->hw.init = &init;
380
381 hw = &clk->hw;
382 ret = clk_hw_register(NULL, hw);
383 if (ret) {
384 kfree(clk);
385 hw = ERR_PTR(ret);
386 }
387
388 return hw;
389 }