xref: /openbmc/linux/drivers/clk/imx/clk-scu.c (revision 3b9ea606)
1fe37b482SAisheng Dong // SPDX-License-Identifier: GPL-2.0+
2fe37b482SAisheng Dong /*
3fe37b482SAisheng Dong  * Copyright 2018 NXP
4fe37b482SAisheng Dong  *   Dong Aisheng <aisheng.dong@nxp.com>
5fe37b482SAisheng Dong  */
6fe37b482SAisheng Dong 
73b9ea606SAnson Huang #include <dt-bindings/firmware/imx/rsrc.h>
83b9ea606SAnson Huang #include <linux/arm-smccc.h>
9fe37b482SAisheng Dong #include <linux/clk-provider.h>
10fe37b482SAisheng Dong #include <linux/err.h>
11fe37b482SAisheng Dong #include <linux/slab.h>
12fe37b482SAisheng Dong 
13fe37b482SAisheng Dong #include "clk-scu.h"
14fe37b482SAisheng Dong 
153b9ea606SAnson Huang #define IMX_SIP_CPUFREQ			0xC2000001
163b9ea606SAnson Huang #define IMX_SIP_SET_CPUFREQ		0x00
173b9ea606SAnson Huang 
18fe37b482SAisheng Dong static struct imx_sc_ipc *ccm_ipc_handle;
19fe37b482SAisheng Dong 
20fe37b482SAisheng Dong /*
21fe37b482SAisheng Dong  * struct clk_scu - Description of one SCU clock
22fe37b482SAisheng Dong  * @hw: the common clk_hw
23fe37b482SAisheng Dong  * @rsrc_id: resource ID of this SCU clock
24fe37b482SAisheng Dong  * @clk_type: type of this clock resource
25fe37b482SAisheng Dong  */
26fe37b482SAisheng Dong struct clk_scu {
27fe37b482SAisheng Dong 	struct clk_hw hw;
28fe37b482SAisheng Dong 	u16 rsrc_id;
29fe37b482SAisheng Dong 	u8 clk_type;
30fe37b482SAisheng Dong };
31fe37b482SAisheng Dong 
32fe37b482SAisheng Dong /*
33fe37b482SAisheng Dong  * struct imx_sc_msg_req_set_clock_rate - clock set rate protocol
34fe37b482SAisheng Dong  * @hdr: SCU protocol header
35fe37b482SAisheng Dong  * @rate: rate to set
36fe37b482SAisheng Dong  * @resource: clock resource to set rate
37fe37b482SAisheng Dong  * @clk: clk type of this resource
38fe37b482SAisheng Dong  *
39fe37b482SAisheng Dong  * This structure describes the SCU protocol of clock rate set
40fe37b482SAisheng Dong  */
41fe37b482SAisheng Dong struct imx_sc_msg_req_set_clock_rate {
42fe37b482SAisheng Dong 	struct imx_sc_rpc_msg hdr;
43fe37b482SAisheng Dong 	__le32 rate;
44fe37b482SAisheng Dong 	__le16 resource;
45fe37b482SAisheng Dong 	u8 clk;
46fe37b482SAisheng Dong } __packed;
47fe37b482SAisheng Dong 
48fe37b482SAisheng Dong struct req_get_clock_rate {
49fe37b482SAisheng Dong 	__le16 resource;
50fe37b482SAisheng Dong 	u8 clk;
51fe37b482SAisheng Dong } __packed;
52fe37b482SAisheng Dong 
53fe37b482SAisheng Dong struct resp_get_clock_rate {
54fe37b482SAisheng Dong 	__le32 rate;
55fe37b482SAisheng Dong };
56fe37b482SAisheng Dong 
57fe37b482SAisheng Dong /*
58fe37b482SAisheng Dong  * struct imx_sc_msg_get_clock_rate - clock get rate protocol
59fe37b482SAisheng Dong  * @hdr: SCU protocol header
60fe37b482SAisheng Dong  * @req: get rate request protocol
61fe37b482SAisheng Dong  * @resp: get rate response protocol
62fe37b482SAisheng Dong  *
63fe37b482SAisheng Dong  * This structure describes the SCU protocol of clock rate get
64fe37b482SAisheng Dong  */
65fe37b482SAisheng Dong struct imx_sc_msg_get_clock_rate {
66fe37b482SAisheng Dong 	struct imx_sc_rpc_msg hdr;
67fe37b482SAisheng Dong 	union {
68fe37b482SAisheng Dong 		struct req_get_clock_rate req;
69fe37b482SAisheng Dong 		struct resp_get_clock_rate resp;
70fe37b482SAisheng Dong 	} data;
71fe37b482SAisheng Dong };
72fe37b482SAisheng Dong 
73fe37b482SAisheng Dong /*
74666aed2dSAisheng Dong  * struct imx_sc_msg_get_clock_parent - clock get parent protocol
75666aed2dSAisheng Dong  * @hdr: SCU protocol header
76666aed2dSAisheng Dong  * @req: get parent request protocol
77666aed2dSAisheng Dong  * @resp: get parent response protocol
78666aed2dSAisheng Dong  *
79666aed2dSAisheng Dong  * This structure describes the SCU protocol of clock get parent
80666aed2dSAisheng Dong  */
81666aed2dSAisheng Dong struct imx_sc_msg_get_clock_parent {
82666aed2dSAisheng Dong 	struct imx_sc_rpc_msg hdr;
83666aed2dSAisheng Dong 	union {
84666aed2dSAisheng Dong 		struct req_get_clock_parent {
85666aed2dSAisheng Dong 			__le16 resource;
86666aed2dSAisheng Dong 			u8 clk;
87666aed2dSAisheng Dong 		} __packed req;
88666aed2dSAisheng Dong 		struct resp_get_clock_parent {
89666aed2dSAisheng Dong 			u8 parent;
90666aed2dSAisheng Dong 		} resp;
91666aed2dSAisheng Dong 	} data;
92666aed2dSAisheng Dong };
93666aed2dSAisheng Dong 
94666aed2dSAisheng Dong /*
95666aed2dSAisheng Dong  * struct imx_sc_msg_set_clock_parent - clock set parent protocol
96666aed2dSAisheng Dong  * @hdr: SCU protocol header
97666aed2dSAisheng Dong  * @req: set parent request protocol
98666aed2dSAisheng Dong  *
99666aed2dSAisheng Dong  * This structure describes the SCU protocol of clock set parent
100666aed2dSAisheng Dong  */
101666aed2dSAisheng Dong struct imx_sc_msg_set_clock_parent {
102666aed2dSAisheng Dong 	struct imx_sc_rpc_msg hdr;
103666aed2dSAisheng Dong 	__le16 resource;
104666aed2dSAisheng Dong 	u8 clk;
105666aed2dSAisheng Dong 	u8 parent;
106666aed2dSAisheng Dong } __packed;
107666aed2dSAisheng Dong 
108666aed2dSAisheng Dong /*
109fe37b482SAisheng Dong  * struct imx_sc_msg_req_clock_enable - clock gate protocol
110fe37b482SAisheng Dong  * @hdr: SCU protocol header
111fe37b482SAisheng Dong  * @resource: clock resource to gate
112fe37b482SAisheng Dong  * @clk: clk type of this resource
113fe37b482SAisheng Dong  * @enable: whether gate off the clock
114fe37b482SAisheng Dong  * @autog: HW auto gate enable
115fe37b482SAisheng Dong  *
116fe37b482SAisheng Dong  * This structure describes the SCU protocol of clock gate
117fe37b482SAisheng Dong  */
118fe37b482SAisheng Dong struct imx_sc_msg_req_clock_enable {
119fe37b482SAisheng Dong 	struct imx_sc_rpc_msg hdr;
120fe37b482SAisheng Dong 	__le16 resource;
121fe37b482SAisheng Dong 	u8 clk;
122fe37b482SAisheng Dong 	u8 enable;
123fe37b482SAisheng Dong 	u8 autog;
124fe37b482SAisheng Dong } __packed;
125fe37b482SAisheng Dong 
126fe37b482SAisheng Dong static inline struct clk_scu *to_clk_scu(struct clk_hw *hw)
127fe37b482SAisheng Dong {
128fe37b482SAisheng Dong 	return container_of(hw, struct clk_scu, hw);
129fe37b482SAisheng Dong }
130fe37b482SAisheng Dong 
131fe37b482SAisheng Dong int imx_clk_scu_init(void)
132fe37b482SAisheng Dong {
133fe37b482SAisheng Dong 	return imx_scu_get_handle(&ccm_ipc_handle);
134fe37b482SAisheng Dong }
135fe37b482SAisheng Dong 
136fe37b482SAisheng Dong /*
137fe37b482SAisheng Dong  * clk_scu_recalc_rate - Get clock rate for a SCU clock
138fe37b482SAisheng Dong  * @hw: clock to get rate for
139fe37b482SAisheng Dong  * @parent_rate: parent rate provided by common clock framework, not used
140fe37b482SAisheng Dong  *
141fe37b482SAisheng Dong  * Gets the current clock rate of a SCU clock. Returns the current
142fe37b482SAisheng Dong  * clock rate, or zero in failure.
143fe37b482SAisheng Dong  */
144fe37b482SAisheng Dong static unsigned long clk_scu_recalc_rate(struct clk_hw *hw,
145fe37b482SAisheng Dong 					 unsigned long parent_rate)
146fe37b482SAisheng Dong {
147fe37b482SAisheng Dong 	struct clk_scu *clk = to_clk_scu(hw);
148fe37b482SAisheng Dong 	struct imx_sc_msg_get_clock_rate msg;
149fe37b482SAisheng Dong 	struct imx_sc_rpc_msg *hdr = &msg.hdr;
150fe37b482SAisheng Dong 	int ret;
151fe37b482SAisheng Dong 
152fe37b482SAisheng Dong 	hdr->ver = IMX_SC_RPC_VERSION;
153fe37b482SAisheng Dong 	hdr->svc = IMX_SC_RPC_SVC_PM;
154fe37b482SAisheng Dong 	hdr->func = IMX_SC_PM_FUNC_GET_CLOCK_RATE;
155fe37b482SAisheng Dong 	hdr->size = 2;
156fe37b482SAisheng Dong 
157fe37b482SAisheng Dong 	msg.data.req.resource = cpu_to_le16(clk->rsrc_id);
158fe37b482SAisheng Dong 	msg.data.req.clk = clk->clk_type;
159fe37b482SAisheng Dong 
160fe37b482SAisheng Dong 	ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
161fe37b482SAisheng Dong 	if (ret) {
162fe37b482SAisheng Dong 		pr_err("%s: failed to get clock rate %d\n",
163fe37b482SAisheng Dong 		       clk_hw_get_name(hw), ret);
164fe37b482SAisheng Dong 		return 0;
165fe37b482SAisheng Dong 	}
166fe37b482SAisheng Dong 
167fe37b482SAisheng Dong 	return le32_to_cpu(msg.data.resp.rate);
168fe37b482SAisheng Dong }
169fe37b482SAisheng Dong 
170fe37b482SAisheng Dong /*
171fe37b482SAisheng Dong  * clk_scu_round_rate - Round clock rate for a SCU clock
172fe37b482SAisheng Dong  * @hw: clock to round rate for
173fe37b482SAisheng Dong  * @rate: rate to round
174fe37b482SAisheng Dong  * @parent_rate: parent rate provided by common clock framework, not used
175fe37b482SAisheng Dong  *
176fe37b482SAisheng Dong  * Returns the current clock rate, or zero in failure.
177fe37b482SAisheng Dong  */
178fe37b482SAisheng Dong static long clk_scu_round_rate(struct clk_hw *hw, unsigned long rate,
179fe37b482SAisheng Dong 			       unsigned long *parent_rate)
180fe37b482SAisheng Dong {
181fe37b482SAisheng Dong 	/*
182fe37b482SAisheng Dong 	 * Assume we support all the requested rate and let the SCU firmware
183fe37b482SAisheng Dong 	 * to handle the left work
184fe37b482SAisheng Dong 	 */
185fe37b482SAisheng Dong 	return rate;
186fe37b482SAisheng Dong }
187fe37b482SAisheng Dong 
1883b9ea606SAnson Huang static int clk_scu_atf_set_cpu_rate(struct clk_hw *hw, unsigned long rate,
1893b9ea606SAnson Huang 				    unsigned long parent_rate)
1903b9ea606SAnson Huang {
1913b9ea606SAnson Huang 	struct clk_scu *clk = to_clk_scu(hw);
1923b9ea606SAnson Huang 	struct arm_smccc_res res;
1933b9ea606SAnson Huang 	unsigned long cluster_id;
1943b9ea606SAnson Huang 
1953b9ea606SAnson Huang 	if (clk->rsrc_id == IMX_SC_R_A35)
1963b9ea606SAnson Huang 		cluster_id = 0;
1973b9ea606SAnson Huang 	else
1983b9ea606SAnson Huang 		return -EINVAL;
1993b9ea606SAnson Huang 
2003b9ea606SAnson Huang 	/* CPU frequency scaling can ONLY be done by ARM-Trusted-Firmware */
2013b9ea606SAnson Huang 	arm_smccc_smc(IMX_SIP_CPUFREQ, IMX_SIP_SET_CPUFREQ,
2023b9ea606SAnson Huang 		      cluster_id, rate, 0, 0, 0, 0, &res);
2033b9ea606SAnson Huang 
2043b9ea606SAnson Huang 	return 0;
2053b9ea606SAnson Huang }
2063b9ea606SAnson Huang 
207fe37b482SAisheng Dong /*
208fe37b482SAisheng Dong  * clk_scu_set_rate - Set rate for a SCU clock
209fe37b482SAisheng Dong  * @hw: clock to change rate for
210fe37b482SAisheng Dong  * @rate: target rate for the clock
211fe37b482SAisheng Dong  * @parent_rate: rate of the clock parent, not used for SCU clocks
212fe37b482SAisheng Dong  *
213fe37b482SAisheng Dong  * Sets a clock frequency for a SCU clock. Returns the SCU
214fe37b482SAisheng Dong  * protocol status.
215fe37b482SAisheng Dong  */
216fe37b482SAisheng Dong static int clk_scu_set_rate(struct clk_hw *hw, unsigned long rate,
217fe37b482SAisheng Dong 			    unsigned long parent_rate)
218fe37b482SAisheng Dong {
219fe37b482SAisheng Dong 	struct clk_scu *clk = to_clk_scu(hw);
220fe37b482SAisheng Dong 	struct imx_sc_msg_req_set_clock_rate msg;
221fe37b482SAisheng Dong 	struct imx_sc_rpc_msg *hdr = &msg.hdr;
222fe37b482SAisheng Dong 
223fe37b482SAisheng Dong 	hdr->ver = IMX_SC_RPC_VERSION;
224fe37b482SAisheng Dong 	hdr->svc = IMX_SC_RPC_SVC_PM;
225fe37b482SAisheng Dong 	hdr->func = IMX_SC_PM_FUNC_SET_CLOCK_RATE;
226fe37b482SAisheng Dong 	hdr->size = 3;
227fe37b482SAisheng Dong 
228fe37b482SAisheng Dong 	msg.rate = cpu_to_le32(rate);
229fe37b482SAisheng Dong 	msg.resource = cpu_to_le16(clk->rsrc_id);
230fe37b482SAisheng Dong 	msg.clk = clk->clk_type;
231fe37b482SAisheng Dong 
232fe37b482SAisheng Dong 	return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
233fe37b482SAisheng Dong }
234fe37b482SAisheng Dong 
235666aed2dSAisheng Dong static u8 clk_scu_get_parent(struct clk_hw *hw)
236666aed2dSAisheng Dong {
237666aed2dSAisheng Dong 	struct clk_scu *clk = to_clk_scu(hw);
238666aed2dSAisheng Dong 	struct imx_sc_msg_get_clock_parent msg;
239666aed2dSAisheng Dong 	struct imx_sc_rpc_msg *hdr = &msg.hdr;
240666aed2dSAisheng Dong 	int ret;
241666aed2dSAisheng Dong 
242666aed2dSAisheng Dong 	hdr->ver = IMX_SC_RPC_VERSION;
243666aed2dSAisheng Dong 	hdr->svc = IMX_SC_RPC_SVC_PM;
244666aed2dSAisheng Dong 	hdr->func = IMX_SC_PM_FUNC_GET_CLOCK_PARENT;
245666aed2dSAisheng Dong 	hdr->size = 2;
246666aed2dSAisheng Dong 
247666aed2dSAisheng Dong 	msg.data.req.resource = cpu_to_le16(clk->rsrc_id);
248666aed2dSAisheng Dong 	msg.data.req.clk = clk->clk_type;
249666aed2dSAisheng Dong 
250666aed2dSAisheng Dong 	ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
251666aed2dSAisheng Dong 	if (ret) {
252666aed2dSAisheng Dong 		pr_err("%s: failed to get clock parent %d\n",
253666aed2dSAisheng Dong 		       clk_hw_get_name(hw), ret);
254666aed2dSAisheng Dong 		return 0;
255666aed2dSAisheng Dong 	}
256666aed2dSAisheng Dong 
257666aed2dSAisheng Dong 	return msg.data.resp.parent;
258666aed2dSAisheng Dong }
259666aed2dSAisheng Dong 
260666aed2dSAisheng Dong static int clk_scu_set_parent(struct clk_hw *hw, u8 index)
261666aed2dSAisheng Dong {
262666aed2dSAisheng Dong 	struct clk_scu *clk = to_clk_scu(hw);
263666aed2dSAisheng Dong 	struct imx_sc_msg_set_clock_parent msg;
264666aed2dSAisheng Dong 	struct imx_sc_rpc_msg *hdr = &msg.hdr;
265666aed2dSAisheng Dong 
266666aed2dSAisheng Dong 	hdr->ver = IMX_SC_RPC_VERSION;
267666aed2dSAisheng Dong 	hdr->svc = IMX_SC_RPC_SVC_PM;
268666aed2dSAisheng Dong 	hdr->func = IMX_SC_PM_FUNC_SET_CLOCK_PARENT;
269666aed2dSAisheng Dong 	hdr->size = 2;
270666aed2dSAisheng Dong 
271666aed2dSAisheng Dong 	msg.resource = cpu_to_le16(clk->rsrc_id);
272666aed2dSAisheng Dong 	msg.clk = clk->clk_type;
273666aed2dSAisheng Dong 	msg.parent = index;
274666aed2dSAisheng Dong 
275666aed2dSAisheng Dong 	return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
276666aed2dSAisheng Dong }
277666aed2dSAisheng Dong 
278fe37b482SAisheng Dong static int sc_pm_clock_enable(struct imx_sc_ipc *ipc, u16 resource,
279fe37b482SAisheng Dong 			      u8 clk, bool enable, bool autog)
280fe37b482SAisheng Dong {
281fe37b482SAisheng Dong 	struct imx_sc_msg_req_clock_enable msg;
282fe37b482SAisheng Dong 	struct imx_sc_rpc_msg *hdr = &msg.hdr;
283fe37b482SAisheng Dong 
284fe37b482SAisheng Dong 	hdr->ver = IMX_SC_RPC_VERSION;
285fe37b482SAisheng Dong 	hdr->svc = IMX_SC_RPC_SVC_PM;
286fe37b482SAisheng Dong 	hdr->func = IMX_SC_PM_FUNC_CLOCK_ENABLE;
287fe37b482SAisheng Dong 	hdr->size = 3;
288fe37b482SAisheng Dong 
289fe37b482SAisheng Dong 	msg.resource = cpu_to_le16(resource);
290fe37b482SAisheng Dong 	msg.clk = clk;
291fe37b482SAisheng Dong 	msg.enable = enable;
292fe37b482SAisheng Dong 	msg.autog = autog;
293fe37b482SAisheng Dong 
294fe37b482SAisheng Dong 	return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
295fe37b482SAisheng Dong }
296fe37b482SAisheng Dong 
297fe37b482SAisheng Dong /*
298fe37b482SAisheng Dong  * clk_scu_prepare - Enable a SCU clock
299fe37b482SAisheng Dong  * @hw: clock to enable
300fe37b482SAisheng Dong  *
301fe37b482SAisheng Dong  * Enable the clock at the DSC slice level
302fe37b482SAisheng Dong  */
303fe37b482SAisheng Dong static int clk_scu_prepare(struct clk_hw *hw)
304fe37b482SAisheng Dong {
305fe37b482SAisheng Dong 	struct clk_scu *clk = to_clk_scu(hw);
306fe37b482SAisheng Dong 
307fe37b482SAisheng Dong 	return sc_pm_clock_enable(ccm_ipc_handle, clk->rsrc_id,
308fe37b482SAisheng Dong 				  clk->clk_type, true, false);
309fe37b482SAisheng Dong }
310fe37b482SAisheng Dong 
311fe37b482SAisheng Dong /*
312fe37b482SAisheng Dong  * clk_scu_unprepare - Disable a SCU clock
313fe37b482SAisheng Dong  * @hw: clock to enable
314fe37b482SAisheng Dong  *
315fe37b482SAisheng Dong  * Disable the clock at the DSC slice level
316fe37b482SAisheng Dong  */
317fe37b482SAisheng Dong static void clk_scu_unprepare(struct clk_hw *hw)
318fe37b482SAisheng Dong {
319fe37b482SAisheng Dong 	struct clk_scu *clk = to_clk_scu(hw);
320fe37b482SAisheng Dong 	int ret;
321fe37b482SAisheng Dong 
322fe37b482SAisheng Dong 	ret = sc_pm_clock_enable(ccm_ipc_handle, clk->rsrc_id,
323fe37b482SAisheng Dong 				 clk->clk_type, false, false);
324fe37b482SAisheng Dong 	if (ret)
325fe37b482SAisheng Dong 		pr_warn("%s: clk unprepare failed %d\n", clk_hw_get_name(hw),
326fe37b482SAisheng Dong 			ret);
327fe37b482SAisheng Dong }
328fe37b482SAisheng Dong 
329fe37b482SAisheng Dong static const struct clk_ops clk_scu_ops = {
330fe37b482SAisheng Dong 	.recalc_rate = clk_scu_recalc_rate,
331fe37b482SAisheng Dong 	.round_rate = clk_scu_round_rate,
332fe37b482SAisheng Dong 	.set_rate = clk_scu_set_rate,
333666aed2dSAisheng Dong 	.get_parent = clk_scu_get_parent,
334666aed2dSAisheng Dong 	.set_parent = clk_scu_set_parent,
335fe37b482SAisheng Dong 	.prepare = clk_scu_prepare,
336fe37b482SAisheng Dong 	.unprepare = clk_scu_unprepare,
337fe37b482SAisheng Dong };
338fe37b482SAisheng Dong 
3393b9ea606SAnson Huang static const struct clk_ops clk_scu_cpu_ops = {
3403b9ea606SAnson Huang 	.recalc_rate = clk_scu_recalc_rate,
3413b9ea606SAnson Huang 	.round_rate = clk_scu_round_rate,
3423b9ea606SAnson Huang 	.set_rate = clk_scu_atf_set_cpu_rate,
3433b9ea606SAnson Huang 	.prepare = clk_scu_prepare,
3443b9ea606SAnson Huang 	.unprepare = clk_scu_unprepare,
3453b9ea606SAnson Huang };
3463b9ea606SAnson Huang 
347666aed2dSAisheng Dong struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
348666aed2dSAisheng Dong 			     int num_parents, u32 rsrc_id, u8 clk_type)
349fe37b482SAisheng Dong {
350fe37b482SAisheng Dong 	struct clk_init_data init;
351fe37b482SAisheng Dong 	struct clk_scu *clk;
352fe37b482SAisheng Dong 	struct clk_hw *hw;
353fe37b482SAisheng Dong 	int ret;
354fe37b482SAisheng Dong 
355fe37b482SAisheng Dong 	clk = kzalloc(sizeof(*clk), GFP_KERNEL);
356fe37b482SAisheng Dong 	if (!clk)
357fe37b482SAisheng Dong 		return ERR_PTR(-ENOMEM);
358fe37b482SAisheng Dong 
359fe37b482SAisheng Dong 	clk->rsrc_id = rsrc_id;
360fe37b482SAisheng Dong 	clk->clk_type = clk_type;
361fe37b482SAisheng Dong 
362fe37b482SAisheng Dong 	init.name = name;
363fe37b482SAisheng Dong 	init.ops = &clk_scu_ops;
3643b9ea606SAnson Huang 	if (rsrc_id == IMX_SC_R_A35)
3653b9ea606SAnson Huang 		init.ops = &clk_scu_cpu_ops;
3663b9ea606SAnson Huang 	else
3673b9ea606SAnson Huang 		init.ops = &clk_scu_ops;
368666aed2dSAisheng Dong 	init.parent_names = parents;
369666aed2dSAisheng Dong 	init.num_parents = num_parents;
370666aed2dSAisheng Dong 
371fe37b482SAisheng Dong 	/*
372fe37b482SAisheng Dong 	 * Note on MX8, the clocks are tightly coupled with power domain
373fe37b482SAisheng Dong 	 * that once the power domain is off, the clock status may be
374fe37b482SAisheng Dong 	 * lost. So we make it NOCACHE to let user to retrieve the real
375fe37b482SAisheng Dong 	 * clock status from HW instead of using the possible invalid
376fe37b482SAisheng Dong 	 * cached rate.
377fe37b482SAisheng Dong 	 */
378fe37b482SAisheng Dong 	init.flags = CLK_GET_RATE_NOCACHE;
379fe37b482SAisheng Dong 	clk->hw.init = &init;
380fe37b482SAisheng Dong 
381fe37b482SAisheng Dong 	hw = &clk->hw;
382fe37b482SAisheng Dong 	ret = clk_hw_register(NULL, hw);
383fe37b482SAisheng Dong 	if (ret) {
384fe37b482SAisheng Dong 		kfree(clk);
385fe37b482SAisheng Dong 		hw = ERR_PTR(ret);
386fe37b482SAisheng Dong 	}
387fe37b482SAisheng Dong 
388fe37b482SAisheng Dong 	return hw;
389fe37b482SAisheng Dong }
390