Commit 3b9ea606 authored by Anson Huang's avatar Anson Huang Committed by Stephen Boyd

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: default avatarAnson Huang <Anson.Huang@nxp.com>
Signed-off-by: default avatarStephen Boyd <sboyd@kernel.org>
parent 341fdf26
...@@ -4,12 +4,17 @@ ...@@ -4,12 +4,17 @@
* Dong Aisheng <aisheng.dong@nxp.com> * Dong Aisheng <aisheng.dong@nxp.com>
*/ */
#include <dt-bindings/firmware/imx/rsrc.h>
#include <linux/arm-smccc.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "clk-scu.h" #include "clk-scu.h"
#define IMX_SIP_CPUFREQ 0xC2000001
#define IMX_SIP_SET_CPUFREQ 0x00
static struct imx_sc_ipc *ccm_ipc_handle; static struct imx_sc_ipc *ccm_ipc_handle;
/* /*
...@@ -180,6 +185,25 @@ static long clk_scu_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -180,6 +185,25 @@ static long clk_scu_round_rate(struct clk_hw *hw, unsigned long rate,
return rate; return rate;
} }
static int clk_scu_atf_set_cpu_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_scu *clk = to_clk_scu(hw);
struct arm_smccc_res res;
unsigned long cluster_id;
if (clk->rsrc_id == IMX_SC_R_A35)
cluster_id = 0;
else
return -EINVAL;
/* CPU frequency scaling can ONLY be done by ARM-Trusted-Firmware */
arm_smccc_smc(IMX_SIP_CPUFREQ, IMX_SIP_SET_CPUFREQ,
cluster_id, rate, 0, 0, 0, 0, &res);
return 0;
}
/* /*
* clk_scu_set_rate - Set rate for a SCU clock * clk_scu_set_rate - Set rate for a SCU clock
* @hw: clock to change rate for * @hw: clock to change rate for
...@@ -312,6 +336,14 @@ static const struct clk_ops clk_scu_ops = { ...@@ -312,6 +336,14 @@ static const struct clk_ops clk_scu_ops = {
.unprepare = clk_scu_unprepare, .unprepare = clk_scu_unprepare,
}; };
static const struct clk_ops clk_scu_cpu_ops = {
.recalc_rate = clk_scu_recalc_rate,
.round_rate = clk_scu_round_rate,
.set_rate = clk_scu_atf_set_cpu_rate,
.prepare = clk_scu_prepare,
.unprepare = clk_scu_unprepare,
};
struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents, struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
int num_parents, u32 rsrc_id, u8 clk_type) int num_parents, u32 rsrc_id, u8 clk_type)
{ {
...@@ -329,6 +361,10 @@ struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents, ...@@ -329,6 +361,10 @@ struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
init.name = name; init.name = name;
init.ops = &clk_scu_ops; init.ops = &clk_scu_ops;
if (rsrc_id == IMX_SC_R_A35)
init.ops = &clk_scu_cpu_ops;
else
init.ops = &clk_scu_ops;
init.parent_names = parents; init.parent_names = parents;
init.num_parents = num_parents; init.num_parents = num_parents;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment