xref: /openbmc/linux/drivers/clk/imx/clk-scu.c (revision 1cac4f26)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2018 NXP
4  *   Dong Aisheng <aisheng.dong@nxp.com>
5  */
6 
7 #include <linux/clk-provider.h>
8 #include <linux/err.h>
9 #include <linux/slab.h>
10 
11 #include "clk-scu.h"
12 
13 static struct imx_sc_ipc *ccm_ipc_handle;
14 
15 /*
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
20  */
21 struct clk_scu {
22 	struct clk_hw hw;
23 	u16 rsrc_id;
24 	u8 clk_type;
25 };
26 
27 /*
28  * struct imx_sc_msg_req_set_clock_rate - clock set rate protocol
29  * @hdr: SCU protocol header
30  * @rate: rate to set
31  * @resource: clock resource to set rate
32  * @clk: clk type of this resource
33  *
34  * This structure describes the SCU protocol of clock rate set
35  */
36 struct imx_sc_msg_req_set_clock_rate {
37 	struct imx_sc_rpc_msg hdr;
38 	__le32 rate;
39 	__le16 resource;
40 	u8 clk;
41 } __packed;
42 
43 struct req_get_clock_rate {
44 	__le16 resource;
45 	u8 clk;
46 } __packed;
47 
48 struct resp_get_clock_rate {
49 	__le32 rate;
50 };
51 
52 /*
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
57  *
58  * This structure describes the SCU protocol of clock rate get
59  */
60 struct imx_sc_msg_get_clock_rate {
61 	struct imx_sc_rpc_msg hdr;
62 	union {
63 		struct req_get_clock_rate req;
64 		struct resp_get_clock_rate resp;
65 	} data;
66 };
67 
68 /*
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
75  *
76  * This structure describes the SCU protocol of clock gate
77  */
78 struct imx_sc_msg_req_clock_enable {
79 	struct imx_sc_rpc_msg hdr;
80 	__le16 resource;
81 	u8 clk;
82 	u8 enable;
83 	u8 autog;
84 } __packed;
85 
86 static inline struct clk_scu *to_clk_scu(struct clk_hw *hw)
87 {
88 	return container_of(hw, struct clk_scu, hw);
89 }
90 
91 int imx_clk_scu_init(void)
92 {
93 	return imx_scu_get_handle(&ccm_ipc_handle);
94 }
95 
96 /*
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
100  *
101  * Gets the current clock rate of a SCU clock. Returns the current
102  * clock rate, or zero in failure.
103  */
104 static unsigned long clk_scu_recalc_rate(struct clk_hw *hw,
105 					 unsigned long parent_rate)
106 {
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;
110 	int ret;
111 
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;
115 	hdr->size = 2;
116 
117 	msg.data.req.resource = cpu_to_le16(clk->rsrc_id);
118 	msg.data.req.clk = clk->clk_type;
119 
120 	ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
121 	if (ret) {
122 		pr_err("%s: failed to get clock rate %d\n",
123 		       clk_hw_get_name(hw), ret);
124 		return 0;
125 	}
126 
127 	return le32_to_cpu(msg.data.resp.rate);
128 }
129 
130 /*
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
135  *
136  * Returns the current clock rate, or zero in failure.
137  */
138 static long clk_scu_round_rate(struct clk_hw *hw, unsigned long rate,
139 			       unsigned long *parent_rate)
140 {
141 	/*
142 	 * Assume we support all the requested rate and let the SCU firmware
143 	 * to handle the left work
144 	 */
145 	return rate;
146 }
147 
148 /*
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
153  *
154  * Sets a clock frequency for a SCU clock. Returns the SCU
155  * protocol status.
156  */
157 static int clk_scu_set_rate(struct clk_hw *hw, unsigned long rate,
158 			    unsigned long parent_rate)
159 {
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;
163 
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;
167 	hdr->size = 3;
168 
169 	msg.rate = cpu_to_le32(rate);
170 	msg.resource = cpu_to_le16(clk->rsrc_id);
171 	msg.clk = clk->clk_type;
172 
173 	return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
174 }
175 
176 static int sc_pm_clock_enable(struct imx_sc_ipc *ipc, u16 resource,
177 			      u8 clk, bool enable, bool autog)
178 {
179 	struct imx_sc_msg_req_clock_enable msg;
180 	struct imx_sc_rpc_msg *hdr = &msg.hdr;
181 
182 	hdr->ver = IMX_SC_RPC_VERSION;
183 	hdr->svc = IMX_SC_RPC_SVC_PM;
184 	hdr->func = IMX_SC_PM_FUNC_CLOCK_ENABLE;
185 	hdr->size = 3;
186 
187 	msg.resource = cpu_to_le16(resource);
188 	msg.clk = clk;
189 	msg.enable = enable;
190 	msg.autog = autog;
191 
192 	return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
193 }
194 
195 /*
196  * clk_scu_prepare - Enable a SCU clock
197  * @hw: clock to enable
198  *
199  * Enable the clock at the DSC slice level
200  */
201 static int clk_scu_prepare(struct clk_hw *hw)
202 {
203 	struct clk_scu *clk = to_clk_scu(hw);
204 
205 	return sc_pm_clock_enable(ccm_ipc_handle, clk->rsrc_id,
206 				  clk->clk_type, true, false);
207 }
208 
209 /*
210  * clk_scu_unprepare - Disable a SCU clock
211  * @hw: clock to enable
212  *
213  * Disable the clock at the DSC slice level
214  */
215 static void clk_scu_unprepare(struct clk_hw *hw)
216 {
217 	struct clk_scu *clk = to_clk_scu(hw);
218 	int ret;
219 
220 	ret = sc_pm_clock_enable(ccm_ipc_handle, clk->rsrc_id,
221 				 clk->clk_type, false, false);
222 	if (ret)
223 		pr_warn("%s: clk unprepare failed %d\n", clk_hw_get_name(hw),
224 			ret);
225 }
226 
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,
233 };
234 
235 struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type)
236 {
237 	struct clk_init_data init;
238 	struct clk_scu *clk;
239 	struct clk_hw *hw;
240 	int ret;
241 
242 	clk = kzalloc(sizeof(*clk), GFP_KERNEL);
243 	if (!clk)
244 		return ERR_PTR(-ENOMEM);
245 
246 	clk->rsrc_id = rsrc_id;
247 	clk->clk_type = clk_type;
248 
249 	init.name = name;
250 	init.ops = &clk_scu_ops;
251 	init.num_parents = 0;
252 	/*
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
257 	 * cached rate.
258 	 */
259 	init.flags = CLK_GET_RATE_NOCACHE;
260 	clk->hw.init = &init;
261 
262 	hw = &clk->hw;
263 	ret = clk_hw_register(NULL, hw);
264 	if (ret) {
265 		kfree(clk);
266 		hw = ERR_PTR(ret);
267 	}
268 
269 	return hw;
270 }
271