1 // SPDX-License-Identifier: GPL-2.0+
4 * Dong Aisheng <aisheng.dong@nxp.com>
7 #include <linux/clk-provider.h>
9 #include <linux/slab.h>
13 static struct imx_sc_ipc *ccm_ipc_handle;
16 * struct clk_scu - Description of one SCU clock
17 * @hw: the common clk_hw
18 * @rsrc_id: resource ID of this SCU clock
19 * @clk_type: type of this clock resource
28 * struct imx_sc_msg_req_set_clock_rate - clock set rate protocol
29 * @hdr: SCU protocol header
31 * @resource: clock resource to set rate
32 * @clk: clk type of this resource
34 * This structure describes the SCU protocol of clock rate set
36 struct imx_sc_msg_req_set_clock_rate {
37 struct imx_sc_rpc_msg hdr;
43 struct req_get_clock_rate {
48 struct resp_get_clock_rate {
53 * struct imx_sc_msg_get_clock_rate - clock get rate protocol
54 * @hdr: SCU protocol header
55 * @req: get rate request protocol
56 * @resp: get rate response protocol
58 * This structure describes the SCU protocol of clock rate get
60 struct imx_sc_msg_get_clock_rate {
61 struct imx_sc_rpc_msg hdr;
63 struct req_get_clock_rate req;
64 struct resp_get_clock_rate resp;
69 * struct imx_sc_msg_req_clock_enable - clock gate protocol
70 * @hdr: SCU protocol header
71 * @resource: clock resource to gate
72 * @clk: clk type of this resource
73 * @enable: whether gate off the clock
74 * @autog: HW auto gate enable
76 * This structure describes the SCU protocol of clock gate
78 struct imx_sc_msg_req_clock_enable {
79 struct imx_sc_rpc_msg hdr;
86 static inline struct clk_scu *to_clk_scu(struct clk_hw *hw)
88 return container_of(hw, struct clk_scu, hw);
91 int imx_clk_scu_init(void)
93 return imx_scu_get_handle(&ccm_ipc_handle);
97 * clk_scu_recalc_rate - Get clock rate for a SCU clock
98 * @hw: clock to get rate for
99 * @parent_rate: parent rate provided by common clock framework, not used
101 * Gets the current clock rate of a SCU clock. Returns the current
102 * clock rate, or zero in failure.
104 static unsigned long clk_scu_recalc_rate(struct clk_hw *hw,
105 unsigned long parent_rate)
107 struct clk_scu *clk = to_clk_scu(hw);
108 struct imx_sc_msg_get_clock_rate msg;
109 struct imx_sc_rpc_msg *hdr = &msg.hdr;
112 hdr->ver = IMX_SC_RPC_VERSION;
113 hdr->svc = IMX_SC_RPC_SVC_PM;
114 hdr->func = IMX_SC_PM_FUNC_GET_CLOCK_RATE;
117 msg.data.req.resource = cpu_to_le16(clk->rsrc_id);
118 msg.data.req.clk = clk->clk_type;
120 ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
122 pr_err("%s: failed to get clock rate %d\n",
123 clk_hw_get_name(hw), ret);
127 return le32_to_cpu(msg.data.resp.rate);
131 * clk_scu_round_rate - Round clock rate for a SCU clock
132 * @hw: clock to round rate for
133 * @rate: rate to round
134 * @parent_rate: parent rate provided by common clock framework, not used
136 * Returns the current clock rate, or zero in failure.
138 static long clk_scu_round_rate(struct clk_hw *hw, unsigned long rate,
139 unsigned long *parent_rate)
142 * Assume we support all the requested rate and let the SCU firmware
143 * to handle the left work
149 * clk_scu_set_rate - Set rate for a SCU clock
150 * @hw: clock to change rate for
151 * @rate: target rate for the clock
152 * @parent_rate: rate of the clock parent, not used for SCU clocks
154 * Sets a clock frequency for a SCU clock. Returns the SCU
157 static int clk_scu_set_rate(struct clk_hw *hw, unsigned long rate,
158 unsigned long parent_rate)
160 struct clk_scu *clk = to_clk_scu(hw);
161 struct imx_sc_msg_req_set_clock_rate msg;
162 struct imx_sc_rpc_msg *hdr = &msg.hdr;
164 hdr->ver = IMX_SC_RPC_VERSION;
165 hdr->svc = IMX_SC_RPC_SVC_PM;
166 hdr->func = IMX_SC_PM_FUNC_SET_CLOCK_RATE;
169 msg.rate = cpu_to_le32(rate);
170 msg.resource = cpu_to_le16(clk->rsrc_id);
171 msg.clk = clk->clk_type;
173 return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
176 static int sc_pm_clock_enable(struct imx_sc_ipc *ipc, u16 resource,
177 u8 clk, bool enable, bool autog)
179 struct imx_sc_msg_req_clock_enable msg;
180 struct imx_sc_rpc_msg *hdr = &msg.hdr;
182 hdr->ver = IMX_SC_RPC_VERSION;
183 hdr->svc = IMX_SC_RPC_SVC_PM;
184 hdr->func = IMX_SC_PM_FUNC_CLOCK_ENABLE;
187 msg.resource = cpu_to_le16(resource);
192 return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
196 * clk_scu_prepare - Enable a SCU clock
197 * @hw: clock to enable
199 * Enable the clock at the DSC slice level
201 static int clk_scu_prepare(struct clk_hw *hw)
203 struct clk_scu *clk = to_clk_scu(hw);
205 return sc_pm_clock_enable(ccm_ipc_handle, clk->rsrc_id,
206 clk->clk_type, true, false);
210 * clk_scu_unprepare - Disable a SCU clock
211 * @hw: clock to enable
213 * Disable the clock at the DSC slice level
215 static void clk_scu_unprepare(struct clk_hw *hw)
217 struct clk_scu *clk = to_clk_scu(hw);
220 ret = sc_pm_clock_enable(ccm_ipc_handle, clk->rsrc_id,
221 clk->clk_type, false, false);
223 pr_warn("%s: clk unprepare failed %d\n", clk_hw_get_name(hw),
227 static const struct clk_ops clk_scu_ops = {
228 .recalc_rate = clk_scu_recalc_rate,
229 .round_rate = clk_scu_round_rate,
230 .set_rate = clk_scu_set_rate,
231 .prepare = clk_scu_prepare,
232 .unprepare = clk_scu_unprepare,
235 struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type)
237 struct clk_init_data init;
242 clk = kzalloc(sizeof(*clk), GFP_KERNEL);
244 return ERR_PTR(-ENOMEM);
246 clk->rsrc_id = rsrc_id;
247 clk->clk_type = clk_type;
250 init.ops = &clk_scu_ops;
251 init.num_parents = 0;
253 * Note on MX8, the clocks are tightly coupled with power domain
254 * that once the power domain is off, the clock status may be
255 * lost. So we make it NOCACHE to let user to retrieve the real
256 * clock status from HW instead of using the possible invalid
259 init.flags = CLK_GET_RATE_NOCACHE;
260 clk->hw.init = &init;
263 ret = clk_hw_register(NULL, hw);