1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2018 NXP 4 * Dong Aisheng <aisheng.dong@nxp.com> 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 * 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 25 */ 26 struct clk_scu { 27 struct clk_hw hw; 28 u16 rsrc_id; 29 u8 clk_type; 30 }; 31 32 /* 33 * struct imx_sc_msg_req_set_clock_rate - clock set rate protocol 34 * @hdr: SCU protocol header 35 * @rate: rate to set 36 * @resource: clock resource to set rate 37 * @clk: clk type of this resource 38 * 39 * This structure describes the SCU protocol of clock rate set 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 * 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 62 * 63 * This structure describes the SCU protocol of clock rate get 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 * 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 78 * 79 * This structure describes the SCU protocol of clock get parent 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 * struct imx_sc_msg_set_clock_parent - clock set parent protocol 96 * @hdr: SCU protocol header 97 * @req: set parent request protocol 98 * 99 * This structure describes the SCU protocol of clock set parent 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 * 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 115 * 116 * This structure describes the SCU protocol of clock gate 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 * 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 140 * 141 * Gets the current clock rate of a SCU clock. Returns the current 142 * clock rate, or zero in failure. 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 * 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 175 * 176 * Returns the current clock rate, or zero in failure. 177 */ 178 static long clk_scu_round_rate(struct clk_hw *hw, unsigned long rate, 179 unsigned long *parent_rate) 180 { 181 /* 182 * Assume we support all the requested rate and let the SCU firmware 183 * to handle the left work 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 /* 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); 203 204 return 0; 205 } 206 207 /* 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 212 * 213 * Sets a clock frequency for a SCU clock. Returns the SCU 214 * protocol status. 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 * clk_scu_prepare - Enable a SCU clock 299 * @hw: clock to enable 300 * 301 * Enable the clock at the DSC slice level 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 * clk_scu_unprepare - Disable a SCU clock 313 * @hw: clock to enable 314 * 315 * Disable the clock at the DSC slice level 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 * 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 376 * cached rate. 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 } 390