root/drivers/clk/imx/clk-scu.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. to_clk_scu
  2. imx_clk_scu_init
  3. clk_scu_recalc_rate
  4. clk_scu_round_rate
  5. clk_scu_atf_set_cpu_rate
  6. clk_scu_set_rate
  7. clk_scu_get_parent
  8. clk_scu_set_parent
  9. sc_pm_clock_enable
  10. clk_scu_prepare
  11. clk_scu_unprepare
  12. __imx_clk_scu

   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 }

/* [<][>][^][v][top][bottom][index][help] */