1 // SPDX-License-Identifier: GPL-2.0+
4 * Dong Aisheng <aisheng.dong@nxp.com>
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>
15 #define IMX_SIP_CPUFREQ 0xC2000001
16 #define IMX_SIP_SET_CPUFREQ 0x00
18 static struct imx_sc_ipc
*ccm_ipc_handle
;
21 * struct clk_scu - Description of one SCU clock
22 * @hw: the common clk_hw
23 * @rsrc_id: resource ID of this SCU clock
24 * @clk_type: type of this clock resource
33 * struct imx_sc_msg_req_set_clock_rate - clock set rate protocol
34 * @hdr: SCU protocol header
36 * @resource: clock resource to set rate
37 * @clk: clk type of this resource
39 * This structure describes the SCU protocol of clock rate set
41 struct imx_sc_msg_req_set_clock_rate
{
42 struct imx_sc_rpc_msg hdr
;
48 struct req_get_clock_rate
{
53 struct resp_get_clock_rate
{
58 * struct imx_sc_msg_get_clock_rate - clock get rate protocol
59 * @hdr: SCU protocol header
60 * @req: get rate request protocol
61 * @resp: get rate response protocol
63 * This structure describes the SCU protocol of clock rate get
65 struct imx_sc_msg_get_clock_rate
{
66 struct imx_sc_rpc_msg hdr
;
68 struct req_get_clock_rate req
;
69 struct resp_get_clock_rate resp
;
74 * struct imx_sc_msg_get_clock_parent - clock get parent protocol
75 * @hdr: SCU protocol header
76 * @req: get parent request protocol
77 * @resp: get parent response protocol
79 * This structure describes the SCU protocol of clock get parent
81 struct imx_sc_msg_get_clock_parent
{
82 struct imx_sc_rpc_msg hdr
;
84 struct req_get_clock_parent
{
88 struct resp_get_clock_parent
{
95 * struct imx_sc_msg_set_clock_parent - clock set parent protocol
96 * @hdr: SCU protocol header
97 * @req: set parent request protocol
99 * This structure describes the SCU protocol of clock set parent
101 struct imx_sc_msg_set_clock_parent
{
102 struct imx_sc_rpc_msg hdr
;
109 * struct imx_sc_msg_req_clock_enable - clock gate protocol
110 * @hdr: SCU protocol header
111 * @resource: clock resource to gate
112 * @clk: clk type of this resource
113 * @enable: whether gate off the clock
114 * @autog: HW auto gate enable
116 * This structure describes the SCU protocol of clock gate
118 struct imx_sc_msg_req_clock_enable
{
119 struct imx_sc_rpc_msg hdr
;
126 static inline struct clk_scu
*to_clk_scu(struct clk_hw
*hw
)
128 return container_of(hw
, struct clk_scu
, hw
);
131 int imx_clk_scu_init(void)
133 return imx_scu_get_handle(&ccm_ipc_handle
);
137 * clk_scu_recalc_rate - Get clock rate for a SCU clock
138 * @hw: clock to get rate for
139 * @parent_rate: parent rate provided by common clock framework, not used
141 * Gets the current clock rate of a SCU clock. Returns the current
142 * clock rate, or zero in failure.
144 static unsigned long clk_scu_recalc_rate(struct clk_hw
*hw
,
145 unsigned long parent_rate
)
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
;
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
;
157 msg
.data
.req
.resource
= cpu_to_le16(clk
->rsrc_id
);
158 msg
.data
.req
.clk
= clk
->clk_type
;
160 ret
= imx_scu_call_rpc(ccm_ipc_handle
, &msg
, true);
162 pr_err("%s: failed to get clock rate %d\n",
163 clk_hw_get_name(hw
), ret
);
167 return le32_to_cpu(msg
.data
.resp
.rate
);
171 * clk_scu_round_rate - Round clock rate for a SCU clock
172 * @hw: clock to round rate for
173 * @rate: rate to round
174 * @parent_rate: parent rate provided by common clock framework, not used
176 * Returns the current clock rate, or zero in failure.
178 static long clk_scu_round_rate(struct clk_hw
*hw
, unsigned long rate
,
179 unsigned long *parent_rate
)
182 * Assume we support all the requested rate and let the SCU firmware
183 * to handle the left work
188 static int clk_scu_atf_set_cpu_rate(struct clk_hw
*hw
, unsigned long rate
,
189 unsigned long parent_rate
)
191 struct clk_scu
*clk
= to_clk_scu(hw
);
192 struct arm_smccc_res res
;
193 unsigned long cluster_id
;
195 if (clk
->rsrc_id
== IMX_SC_R_A35
)
200 /* CPU frequency scaling can ONLY be done by ARM-Trusted-Firmware */
201 arm_smccc_smc(IMX_SIP_CPUFREQ
, IMX_SIP_SET_CPUFREQ
,
202 cluster_id
, rate
, 0, 0, 0, 0, &res
);
208 * clk_scu_set_rate - Set rate for a SCU clock
209 * @hw: clock to change rate for
210 * @rate: target rate for the clock
211 * @parent_rate: rate of the clock parent, not used for SCU clocks
213 * Sets a clock frequency for a SCU clock. Returns the SCU
216 static int clk_scu_set_rate(struct clk_hw
*hw
, unsigned long rate
,
217 unsigned long parent_rate
)
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
;
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
;
228 msg
.rate
= cpu_to_le32(rate
);
229 msg
.resource
= cpu_to_le16(clk
->rsrc_id
);
230 msg
.clk
= clk
->clk_type
;
232 return imx_scu_call_rpc(ccm_ipc_handle
, &msg
, true);
235 static u8
clk_scu_get_parent(struct clk_hw
*hw
)
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
;
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
;
247 msg
.data
.req
.resource
= cpu_to_le16(clk
->rsrc_id
);
248 msg
.data
.req
.clk
= clk
->clk_type
;
250 ret
= imx_scu_call_rpc(ccm_ipc_handle
, &msg
, true);
252 pr_err("%s: failed to get clock parent %d\n",
253 clk_hw_get_name(hw
), ret
);
257 return msg
.data
.resp
.parent
;
260 static int clk_scu_set_parent(struct clk_hw
*hw
, u8 index
)
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
;
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
;
271 msg
.resource
= cpu_to_le16(clk
->rsrc_id
);
272 msg
.clk
= clk
->clk_type
;
275 return imx_scu_call_rpc(ccm_ipc_handle
, &msg
, true);
278 static int sc_pm_clock_enable(struct imx_sc_ipc
*ipc
, u16 resource
,
279 u8 clk
, bool enable
, bool autog
)
281 struct imx_sc_msg_req_clock_enable msg
;
282 struct imx_sc_rpc_msg
*hdr
= &msg
.hdr
;
284 hdr
->ver
= IMX_SC_RPC_VERSION
;
285 hdr
->svc
= IMX_SC_RPC_SVC_PM
;
286 hdr
->func
= IMX_SC_PM_FUNC_CLOCK_ENABLE
;
289 msg
.resource
= cpu_to_le16(resource
);
294 return imx_scu_call_rpc(ccm_ipc_handle
, &msg
, true);
298 * clk_scu_prepare - Enable a SCU clock
299 * @hw: clock to enable
301 * Enable the clock at the DSC slice level
303 static int clk_scu_prepare(struct clk_hw
*hw
)
305 struct clk_scu
*clk
= to_clk_scu(hw
);
307 return sc_pm_clock_enable(ccm_ipc_handle
, clk
->rsrc_id
,
308 clk
->clk_type
, true, false);
312 * clk_scu_unprepare - Disable a SCU clock
313 * @hw: clock to enable
315 * Disable the clock at the DSC slice level
317 static void clk_scu_unprepare(struct clk_hw
*hw
)
319 struct clk_scu
*clk
= to_clk_scu(hw
);
322 ret
= sc_pm_clock_enable(ccm_ipc_handle
, clk
->rsrc_id
,
323 clk
->clk_type
, false, false);
325 pr_warn("%s: clk unprepare failed %d\n", clk_hw_get_name(hw
),
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
,
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
,
347 struct clk_hw
*__imx_clk_scu(const char *name
, const char * const *parents
,
348 int num_parents
, u32 rsrc_id
, u8 clk_type
)
350 struct clk_init_data init
;
355 clk
= kzalloc(sizeof(*clk
), GFP_KERNEL
);
357 return ERR_PTR(-ENOMEM
);
359 clk
->rsrc_id
= rsrc_id
;
360 clk
->clk_type
= clk_type
;
363 init
.ops
= &clk_scu_ops
;
364 if (rsrc_id
== IMX_SC_R_A35
)
365 init
.ops
= &clk_scu_cpu_ops
;
367 init
.ops
= &clk_scu_ops
;
368 init
.parent_names
= parents
;
369 init
.num_parents
= num_parents
;
372 * Note on MX8, the clocks are tightly coupled with power domain
373 * that once the power domain is off, the clock status may be
374 * lost. So we make it NOCACHE to let user to retrieve the real
375 * clock status from HW instead of using the possible invalid
378 init
.flags
= CLK_GET_RATE_NOCACHE
;
379 clk
->hw
.init
= &init
;
382 ret
= clk_hw_register(NULL
, hw
);