aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnson Huang <anson.huang@nxp.com>2019-02-26 00:17:36 -0500
committerStephen Boyd <sboyd@kernel.org>2019-02-26 13:03:38 -0500
commit3b9ea606cda533964985966ad5b30715da7ba097 (patch)
tree00a05ac93e901ae7535dadfaf9bb591aa2b72c81
parent341fdf2602113a3fd8e05046e2b7a75b5c0f308e (diff)
clk: imx: scu: add cpu frequency scaling support
On NXP's i.MX SoCs with system controller inside, CPU frequency scaling can ONLY be done by system controller firmware, and it can ONLY be requested from secure mode, so Linux kernel has to call ARM SMC to trap to ARM-Trusted-Firmware to request system controller firmware to do CPU frequency scaling. This patch adds i.MX system controller CPU frequency scaling support, it reuses cpufreq-dt driver and implement the CPU frequency scaling inside SCU clock driver. Signed-off-by: Anson Huang <Anson.Huang@nxp.com> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
-rw-r--r--drivers/clk/imx/clk-scu.c36
1 files changed, 36 insertions, 0 deletions
diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c
index f460526a7abb..fbef740704d0 100644
--- a/drivers/clk/imx/clk-scu.c
+++ b/drivers/clk/imx/clk-scu.c
@@ -4,12 +4,17 @@
4 * Dong Aisheng <aisheng.dong@nxp.com> 4 * Dong Aisheng <aisheng.dong@nxp.com>
5 */ 5 */
6 6
7#include <dt-bindings/firmware/imx/rsrc.h>
8#include <linux/arm-smccc.h>
7#include <linux/clk-provider.h> 9#include <linux/clk-provider.h>
8#include <linux/err.h> 10#include <linux/err.h>
9#include <linux/slab.h> 11#include <linux/slab.h>
10 12
11#include "clk-scu.h" 13#include "clk-scu.h"
12 14
15#define IMX_SIP_CPUFREQ 0xC2000001
16#define IMX_SIP_SET_CPUFREQ 0x00
17
13static struct imx_sc_ipc *ccm_ipc_handle; 18static struct imx_sc_ipc *ccm_ipc_handle;
14 19
15/* 20/*
@@ -180,6 +185,25 @@ static long clk_scu_round_rate(struct clk_hw *hw, unsigned long rate,
180 return rate; 185 return rate;
181} 186}
182 187
188static 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
183/* 207/*
184 * clk_scu_set_rate - Set rate for a SCU clock 208 * clk_scu_set_rate - Set rate for a SCU clock
185 * @hw: clock to change rate for 209 * @hw: clock to change rate for
@@ -312,6 +336,14 @@ static const struct clk_ops clk_scu_ops = {
312 .unprepare = clk_scu_unprepare, 336 .unprepare = clk_scu_unprepare,
313}; 337};
314 338
339static 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
315struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents, 347struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
316 int num_parents, u32 rsrc_id, u8 clk_type) 348 int num_parents, u32 rsrc_id, u8 clk_type)
317{ 349{
@@ -329,6 +361,10 @@ struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
329 361
330 init.name = name; 362 init.name = name;
331 init.ops = &clk_scu_ops; 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;
332 init.parent_names = parents; 368 init.parent_names = parents;
333 init.num_parents = num_parents; 369 init.num_parents = num_parents;
334 370