18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2018 NXP 48c2ecf20Sopenharmony_ci * Dong Aisheng <aisheng.dong@nxp.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <dt-bindings/firmware/imx/rsrc.h> 88c2ecf20Sopenharmony_ci#include <linux/arm-smccc.h> 98c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 108c2ecf20Sopenharmony_ci#include <linux/err.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "clk-scu.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define IMX_SIP_CPUFREQ 0xC2000001 168c2ecf20Sopenharmony_ci#define IMX_SIP_SET_CPUFREQ 0x00 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic struct imx_sc_ipc *ccm_ipc_handle; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* 218c2ecf20Sopenharmony_ci * struct clk_scu - Description of one SCU clock 228c2ecf20Sopenharmony_ci * @hw: the common clk_hw 238c2ecf20Sopenharmony_ci * @rsrc_id: resource ID of this SCU clock 248c2ecf20Sopenharmony_ci * @clk_type: type of this clock resource 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_cistruct clk_scu { 278c2ecf20Sopenharmony_ci struct clk_hw hw; 288c2ecf20Sopenharmony_ci u16 rsrc_id; 298c2ecf20Sopenharmony_ci u8 clk_type; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * struct imx_sc_msg_req_set_clock_rate - clock set rate protocol 348c2ecf20Sopenharmony_ci * @hdr: SCU protocol header 358c2ecf20Sopenharmony_ci * @rate: rate to set 368c2ecf20Sopenharmony_ci * @resource: clock resource to set rate 378c2ecf20Sopenharmony_ci * @clk: clk type of this resource 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * This structure describes the SCU protocol of clock rate set 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_cistruct imx_sc_msg_req_set_clock_rate { 428c2ecf20Sopenharmony_ci struct imx_sc_rpc_msg hdr; 438c2ecf20Sopenharmony_ci __le32 rate; 448c2ecf20Sopenharmony_ci __le16 resource; 458c2ecf20Sopenharmony_ci u8 clk; 468c2ecf20Sopenharmony_ci} __packed __aligned(4); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistruct req_get_clock_rate { 498c2ecf20Sopenharmony_ci __le16 resource; 508c2ecf20Sopenharmony_ci u8 clk; 518c2ecf20Sopenharmony_ci} __packed __aligned(4); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistruct resp_get_clock_rate { 548c2ecf20Sopenharmony_ci __le32 rate; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* 588c2ecf20Sopenharmony_ci * struct imx_sc_msg_get_clock_rate - clock get rate protocol 598c2ecf20Sopenharmony_ci * @hdr: SCU protocol header 608c2ecf20Sopenharmony_ci * @req: get rate request protocol 618c2ecf20Sopenharmony_ci * @resp: get rate response protocol 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * This structure describes the SCU protocol of clock rate get 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_cistruct imx_sc_msg_get_clock_rate { 668c2ecf20Sopenharmony_ci struct imx_sc_rpc_msg hdr; 678c2ecf20Sopenharmony_ci union { 688c2ecf20Sopenharmony_ci struct req_get_clock_rate req; 698c2ecf20Sopenharmony_ci struct resp_get_clock_rate resp; 708c2ecf20Sopenharmony_ci } data; 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* 748c2ecf20Sopenharmony_ci * struct imx_sc_msg_get_clock_parent - clock get parent protocol 758c2ecf20Sopenharmony_ci * @hdr: SCU protocol header 768c2ecf20Sopenharmony_ci * @req: get parent request protocol 778c2ecf20Sopenharmony_ci * @resp: get parent response protocol 788c2ecf20Sopenharmony_ci * 798c2ecf20Sopenharmony_ci * This structure describes the SCU protocol of clock get parent 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_cistruct imx_sc_msg_get_clock_parent { 828c2ecf20Sopenharmony_ci struct imx_sc_rpc_msg hdr; 838c2ecf20Sopenharmony_ci union { 848c2ecf20Sopenharmony_ci struct req_get_clock_parent { 858c2ecf20Sopenharmony_ci __le16 resource; 868c2ecf20Sopenharmony_ci u8 clk; 878c2ecf20Sopenharmony_ci } __packed __aligned(4) req; 888c2ecf20Sopenharmony_ci struct resp_get_clock_parent { 898c2ecf20Sopenharmony_ci u8 parent; 908c2ecf20Sopenharmony_ci } resp; 918c2ecf20Sopenharmony_ci } data; 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* 958c2ecf20Sopenharmony_ci * struct imx_sc_msg_set_clock_parent - clock set parent protocol 968c2ecf20Sopenharmony_ci * @hdr: SCU protocol header 978c2ecf20Sopenharmony_ci * @req: set parent request protocol 988c2ecf20Sopenharmony_ci * 998c2ecf20Sopenharmony_ci * This structure describes the SCU protocol of clock set parent 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_cistruct imx_sc_msg_set_clock_parent { 1028c2ecf20Sopenharmony_ci struct imx_sc_rpc_msg hdr; 1038c2ecf20Sopenharmony_ci __le16 resource; 1048c2ecf20Sopenharmony_ci u8 clk; 1058c2ecf20Sopenharmony_ci u8 parent; 1068c2ecf20Sopenharmony_ci} __packed; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/* 1098c2ecf20Sopenharmony_ci * struct imx_sc_msg_req_clock_enable - clock gate protocol 1108c2ecf20Sopenharmony_ci * @hdr: SCU protocol header 1118c2ecf20Sopenharmony_ci * @resource: clock resource to gate 1128c2ecf20Sopenharmony_ci * @clk: clk type of this resource 1138c2ecf20Sopenharmony_ci * @enable: whether gate off the clock 1148c2ecf20Sopenharmony_ci * @autog: HW auto gate enable 1158c2ecf20Sopenharmony_ci * 1168c2ecf20Sopenharmony_ci * This structure describes the SCU protocol of clock gate 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_cistruct imx_sc_msg_req_clock_enable { 1198c2ecf20Sopenharmony_ci struct imx_sc_rpc_msg hdr; 1208c2ecf20Sopenharmony_ci __le16 resource; 1218c2ecf20Sopenharmony_ci u8 clk; 1228c2ecf20Sopenharmony_ci u8 enable; 1238c2ecf20Sopenharmony_ci u8 autog; 1248c2ecf20Sopenharmony_ci} __packed __aligned(4); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic inline struct clk_scu *to_clk_scu(struct clk_hw *hw) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci return container_of(hw, struct clk_scu, hw); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ciint imx_clk_scu_init(void) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci return imx_scu_get_handle(&ccm_ipc_handle); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* 1378c2ecf20Sopenharmony_ci * clk_scu_recalc_rate - Get clock rate for a SCU clock 1388c2ecf20Sopenharmony_ci * @hw: clock to get rate for 1398c2ecf20Sopenharmony_ci * @parent_rate: parent rate provided by common clock framework, not used 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci * Gets the current clock rate of a SCU clock. Returns the current 1428c2ecf20Sopenharmony_ci * clock rate, or zero in failure. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_cistatic unsigned long clk_scu_recalc_rate(struct clk_hw *hw, 1458c2ecf20Sopenharmony_ci unsigned long parent_rate) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct clk_scu *clk = to_clk_scu(hw); 1488c2ecf20Sopenharmony_ci struct imx_sc_msg_get_clock_rate msg; 1498c2ecf20Sopenharmony_ci struct imx_sc_rpc_msg *hdr = &msg.hdr; 1508c2ecf20Sopenharmony_ci int ret; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci hdr->ver = IMX_SC_RPC_VERSION; 1538c2ecf20Sopenharmony_ci hdr->svc = IMX_SC_RPC_SVC_PM; 1548c2ecf20Sopenharmony_ci hdr->func = IMX_SC_PM_FUNC_GET_CLOCK_RATE; 1558c2ecf20Sopenharmony_ci hdr->size = 2; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci msg.data.req.resource = cpu_to_le16(clk->rsrc_id); 1588c2ecf20Sopenharmony_ci msg.data.req.clk = clk->clk_type; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true); 1618c2ecf20Sopenharmony_ci if (ret) { 1628c2ecf20Sopenharmony_ci pr_err("%s: failed to get clock rate %d\n", 1638c2ecf20Sopenharmony_ci clk_hw_get_name(hw), ret); 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return le32_to_cpu(msg.data.resp.rate); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/* 1718c2ecf20Sopenharmony_ci * clk_scu_round_rate - Round clock rate for a SCU clock 1728c2ecf20Sopenharmony_ci * @hw: clock to round rate for 1738c2ecf20Sopenharmony_ci * @rate: rate to round 1748c2ecf20Sopenharmony_ci * @parent_rate: parent rate provided by common clock framework, not used 1758c2ecf20Sopenharmony_ci * 1768c2ecf20Sopenharmony_ci * Returns the current clock rate, or zero in failure. 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_cistatic long clk_scu_round_rate(struct clk_hw *hw, unsigned long rate, 1798c2ecf20Sopenharmony_ci unsigned long *parent_rate) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci /* 1828c2ecf20Sopenharmony_ci * Assume we support all the requested rate and let the SCU firmware 1838c2ecf20Sopenharmony_ci * to handle the left work 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci return rate; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int clk_scu_atf_set_cpu_rate(struct clk_hw *hw, unsigned long rate, 1898c2ecf20Sopenharmony_ci unsigned long parent_rate) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct clk_scu *clk = to_clk_scu(hw); 1928c2ecf20Sopenharmony_ci struct arm_smccc_res res; 1938c2ecf20Sopenharmony_ci unsigned long cluster_id; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (clk->rsrc_id == IMX_SC_R_A35) 1968c2ecf20Sopenharmony_ci cluster_id = 0; 1978c2ecf20Sopenharmony_ci else 1988c2ecf20Sopenharmony_ci return -EINVAL; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* CPU frequency scaling can ONLY be done by ARM-Trusted-Firmware */ 2018c2ecf20Sopenharmony_ci arm_smccc_smc(IMX_SIP_CPUFREQ, IMX_SIP_SET_CPUFREQ, 2028c2ecf20Sopenharmony_ci cluster_id, rate, 0, 0, 0, 0, &res); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* 2088c2ecf20Sopenharmony_ci * clk_scu_set_rate - Set rate for a SCU clock 2098c2ecf20Sopenharmony_ci * @hw: clock to change rate for 2108c2ecf20Sopenharmony_ci * @rate: target rate for the clock 2118c2ecf20Sopenharmony_ci * @parent_rate: rate of the clock parent, not used for SCU clocks 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci * Sets a clock frequency for a SCU clock. Returns the SCU 2148c2ecf20Sopenharmony_ci * protocol status. 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_cistatic int clk_scu_set_rate(struct clk_hw *hw, unsigned long rate, 2178c2ecf20Sopenharmony_ci unsigned long parent_rate) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct clk_scu *clk = to_clk_scu(hw); 2208c2ecf20Sopenharmony_ci struct imx_sc_msg_req_set_clock_rate msg; 2218c2ecf20Sopenharmony_ci struct imx_sc_rpc_msg *hdr = &msg.hdr; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci hdr->ver = IMX_SC_RPC_VERSION; 2248c2ecf20Sopenharmony_ci hdr->svc = IMX_SC_RPC_SVC_PM; 2258c2ecf20Sopenharmony_ci hdr->func = IMX_SC_PM_FUNC_SET_CLOCK_RATE; 2268c2ecf20Sopenharmony_ci hdr->size = 3; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci msg.rate = cpu_to_le32(rate); 2298c2ecf20Sopenharmony_ci msg.resource = cpu_to_le16(clk->rsrc_id); 2308c2ecf20Sopenharmony_ci msg.clk = clk->clk_type; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return imx_scu_call_rpc(ccm_ipc_handle, &msg, true); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic u8 clk_scu_get_parent(struct clk_hw *hw) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct clk_scu *clk = to_clk_scu(hw); 2388c2ecf20Sopenharmony_ci struct imx_sc_msg_get_clock_parent msg; 2398c2ecf20Sopenharmony_ci struct imx_sc_rpc_msg *hdr = &msg.hdr; 2408c2ecf20Sopenharmony_ci int ret; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci hdr->ver = IMX_SC_RPC_VERSION; 2438c2ecf20Sopenharmony_ci hdr->svc = IMX_SC_RPC_SVC_PM; 2448c2ecf20Sopenharmony_ci hdr->func = IMX_SC_PM_FUNC_GET_CLOCK_PARENT; 2458c2ecf20Sopenharmony_ci hdr->size = 2; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci msg.data.req.resource = cpu_to_le16(clk->rsrc_id); 2488c2ecf20Sopenharmony_ci msg.data.req.clk = clk->clk_type; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true); 2518c2ecf20Sopenharmony_ci if (ret) { 2528c2ecf20Sopenharmony_ci pr_err("%s: failed to get clock parent %d\n", 2538c2ecf20Sopenharmony_ci clk_hw_get_name(hw), ret); 2548c2ecf20Sopenharmony_ci return 0; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return msg.data.resp.parent; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int clk_scu_set_parent(struct clk_hw *hw, u8 index) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct clk_scu *clk = to_clk_scu(hw); 2638c2ecf20Sopenharmony_ci struct imx_sc_msg_set_clock_parent msg; 2648c2ecf20Sopenharmony_ci struct imx_sc_rpc_msg *hdr = &msg.hdr; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci hdr->ver = IMX_SC_RPC_VERSION; 2678c2ecf20Sopenharmony_ci hdr->svc = IMX_SC_RPC_SVC_PM; 2688c2ecf20Sopenharmony_ci hdr->func = IMX_SC_PM_FUNC_SET_CLOCK_PARENT; 2698c2ecf20Sopenharmony_ci hdr->size = 2; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci msg.resource = cpu_to_le16(clk->rsrc_id); 2728c2ecf20Sopenharmony_ci msg.clk = clk->clk_type; 2738c2ecf20Sopenharmony_ci msg.parent = index; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci return imx_scu_call_rpc(ccm_ipc_handle, &msg, true); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic int sc_pm_clock_enable(struct imx_sc_ipc *ipc, u16 resource, 2798c2ecf20Sopenharmony_ci u8 clk, bool enable, bool autog) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct imx_sc_msg_req_clock_enable msg; 2828c2ecf20Sopenharmony_ci struct imx_sc_rpc_msg *hdr = &msg.hdr; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci hdr->ver = IMX_SC_RPC_VERSION; 2858c2ecf20Sopenharmony_ci hdr->svc = IMX_SC_RPC_SVC_PM; 2868c2ecf20Sopenharmony_ci hdr->func = IMX_SC_PM_FUNC_CLOCK_ENABLE; 2878c2ecf20Sopenharmony_ci hdr->size = 3; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci msg.resource = cpu_to_le16(resource); 2908c2ecf20Sopenharmony_ci msg.clk = clk; 2918c2ecf20Sopenharmony_ci msg.enable = enable; 2928c2ecf20Sopenharmony_ci msg.autog = autog; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci return imx_scu_call_rpc(ccm_ipc_handle, &msg, true); 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci/* 2988c2ecf20Sopenharmony_ci * clk_scu_prepare - Enable a SCU clock 2998c2ecf20Sopenharmony_ci * @hw: clock to enable 3008c2ecf20Sopenharmony_ci * 3018c2ecf20Sopenharmony_ci * Enable the clock at the DSC slice level 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_cistatic int clk_scu_prepare(struct clk_hw *hw) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct clk_scu *clk = to_clk_scu(hw); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci return sc_pm_clock_enable(ccm_ipc_handle, clk->rsrc_id, 3088c2ecf20Sopenharmony_ci clk->clk_type, true, false); 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/* 3128c2ecf20Sopenharmony_ci * clk_scu_unprepare - Disable a SCU clock 3138c2ecf20Sopenharmony_ci * @hw: clock to enable 3148c2ecf20Sopenharmony_ci * 3158c2ecf20Sopenharmony_ci * Disable the clock at the DSC slice level 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_cistatic void clk_scu_unprepare(struct clk_hw *hw) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct clk_scu *clk = to_clk_scu(hw); 3208c2ecf20Sopenharmony_ci int ret; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci ret = sc_pm_clock_enable(ccm_ipc_handle, clk->rsrc_id, 3238c2ecf20Sopenharmony_ci clk->clk_type, false, false); 3248c2ecf20Sopenharmony_ci if (ret) 3258c2ecf20Sopenharmony_ci pr_warn("%s: clk unprepare failed %d\n", clk_hw_get_name(hw), 3268c2ecf20Sopenharmony_ci ret); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic const struct clk_ops clk_scu_ops = { 3308c2ecf20Sopenharmony_ci .recalc_rate = clk_scu_recalc_rate, 3318c2ecf20Sopenharmony_ci .round_rate = clk_scu_round_rate, 3328c2ecf20Sopenharmony_ci .set_rate = clk_scu_set_rate, 3338c2ecf20Sopenharmony_ci .get_parent = clk_scu_get_parent, 3348c2ecf20Sopenharmony_ci .set_parent = clk_scu_set_parent, 3358c2ecf20Sopenharmony_ci .prepare = clk_scu_prepare, 3368c2ecf20Sopenharmony_ci .unprepare = clk_scu_unprepare, 3378c2ecf20Sopenharmony_ci}; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic const struct clk_ops clk_scu_cpu_ops = { 3408c2ecf20Sopenharmony_ci .recalc_rate = clk_scu_recalc_rate, 3418c2ecf20Sopenharmony_ci .round_rate = clk_scu_round_rate, 3428c2ecf20Sopenharmony_ci .set_rate = clk_scu_atf_set_cpu_rate, 3438c2ecf20Sopenharmony_ci .prepare = clk_scu_prepare, 3448c2ecf20Sopenharmony_ci .unprepare = clk_scu_unprepare, 3458c2ecf20Sopenharmony_ci}; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistruct clk_hw *__imx_clk_scu(const char *name, const char * const *parents, 3488c2ecf20Sopenharmony_ci int num_parents, u32 rsrc_id, u8 clk_type) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct clk_init_data init; 3518c2ecf20Sopenharmony_ci struct clk_scu *clk; 3528c2ecf20Sopenharmony_ci struct clk_hw *hw; 3538c2ecf20Sopenharmony_ci int ret; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci clk = kzalloc(sizeof(*clk), GFP_KERNEL); 3568c2ecf20Sopenharmony_ci if (!clk) 3578c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci clk->rsrc_id = rsrc_id; 3608c2ecf20Sopenharmony_ci clk->clk_type = clk_type; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci init.name = name; 3638c2ecf20Sopenharmony_ci init.ops = &clk_scu_ops; 3648c2ecf20Sopenharmony_ci if (rsrc_id == IMX_SC_R_A35) 3658c2ecf20Sopenharmony_ci init.ops = &clk_scu_cpu_ops; 3668c2ecf20Sopenharmony_ci else 3678c2ecf20Sopenharmony_ci init.ops = &clk_scu_ops; 3688c2ecf20Sopenharmony_ci init.parent_names = parents; 3698c2ecf20Sopenharmony_ci init.num_parents = num_parents; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* 3728c2ecf20Sopenharmony_ci * Note on MX8, the clocks are tightly coupled with power domain 3738c2ecf20Sopenharmony_ci * that once the power domain is off, the clock status may be 3748c2ecf20Sopenharmony_ci * lost. So we make it NOCACHE to let user to retrieve the real 3758c2ecf20Sopenharmony_ci * clock status from HW instead of using the possible invalid 3768c2ecf20Sopenharmony_ci * cached rate. 3778c2ecf20Sopenharmony_ci */ 3788c2ecf20Sopenharmony_ci init.flags = CLK_GET_RATE_NOCACHE; 3798c2ecf20Sopenharmony_ci clk->hw.init = &init; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci hw = &clk->hw; 3828c2ecf20Sopenharmony_ci ret = clk_hw_register(NULL, hw); 3838c2ecf20Sopenharmony_ci if (ret) { 3848c2ecf20Sopenharmony_ci kfree(clk); 3858c2ecf20Sopenharmony_ci hw = ERR_PTR(ret); 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci return hw; 3898c2ecf20Sopenharmony_ci} 390