clk: imx: Add A72 cluster cpufreq support
Add A72 clock to support cpufreq on A72 cluster, and adding cpufreq governor switch for i.MX8QM which has 2 clusters, in the late phase of kernel boot up, cpufreq governor will be switched to shedutil which is much more suitable for multi-clusters SoCs. Signed-off-by: Anson Huang <Anson.Huang@nxp.com>5.4-rM2-2.2.x-imx-squashed
parent
754fce578f
commit
333db80efd
|
@ -88,6 +88,7 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
|
|||
/* ARM core */
|
||||
imx_clk_scu("a35_clk", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU);
|
||||
imx_clk_scu("a53_clk", IMX_SC_R_A53, IMX_SC_PM_CLK_CPU);
|
||||
imx_clk_scu("a72_clk", IMX_SC_R_A72, IMX_SC_PM_CLK_CPU);
|
||||
|
||||
/* LSIO SS */
|
||||
imx_clk_scu("pwm0_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER);
|
||||
|
|
|
@ -14,14 +14,17 @@
|
|||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/syscalls.h>
|
||||
|
||||
#include "clk-scu.h"
|
||||
|
||||
#define IMX_SIP_CPUFREQ 0xC2000001
|
||||
#define IMX_SIP_SET_CPUFREQ 0x00
|
||||
#define MAX_CLUSTER_NUM 2
|
||||
|
||||
static struct imx_sc_ipc *ccm_ipc_handle;
|
||||
static const struct imx_clk_scu_rsrc_table *rsrc_table;
|
||||
static struct delayed_work cpufreq_governor_daemon;
|
||||
struct device_node *pd_np;
|
||||
u32 clock_cells;
|
||||
|
||||
|
@ -275,6 +278,8 @@ static int clk_scu_atf_set_cpu_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
if (clk->rsrc_id == IMX_SC_R_A35 || clk->rsrc_id == IMX_SC_R_A53)
|
||||
cluster_id = 0;
|
||||
else if (clk->rsrc_id == IMX_SC_R_A72)
|
||||
cluster_id = 1;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -449,7 +454,7 @@ struct clk_hw *__imx_clk_scu(struct device *dev, const char *name,
|
|||
|
||||
init.name = name;
|
||||
init.ops = &clk_scu_ops;
|
||||
if (rsrc_id == IMX_SC_R_A35 || rsrc_id == IMX_SC_R_A53)
|
||||
if (rsrc_id == IMX_SC_R_A35 || rsrc_id == IMX_SC_R_A53 || rsrc_id == IMX_SC_R_A72)
|
||||
init.ops = &clk_scu_cpu_ops;
|
||||
else if (rsrc_id == IMX_SC_R_PI_0_PLL)
|
||||
init.ops = &clk_scu_pi_ops;
|
||||
|
@ -837,3 +842,53 @@ struct clk_hw *__imx_clk_gpr_scu(const char *name, const char * const *parent_na
|
|||
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void cpufreq_governor_daemon_handler(struct work_struct *work)
|
||||
{
|
||||
int fd, i;
|
||||
unsigned char cluster_governor[MAX_CLUSTER_NUM][54] = {
|
||||
"/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor",
|
||||
"",
|
||||
};
|
||||
|
||||
/* generate second cluster's cpufreq governor path */
|
||||
sprintf(cluster_governor[MAX_CLUSTER_NUM - 1],
|
||||
"%s%d%s", "/sys/devices/system/cpu/cpu", num_online_cpus() - 1,
|
||||
"/cpufreq/scaling_governor");
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NUM; i++) {
|
||||
fd = ksys_open((const char __user __force *)cluster_governor[i],
|
||||
O_RDWR, 0700);
|
||||
if (fd >= 0) {
|
||||
ksys_write(fd, "schedutil", strlen("schedutil"));
|
||||
ksys_close(fd);
|
||||
pr_info("switch cluster %d cpu-freq governor to schedutil\n",
|
||||
i);
|
||||
} else {
|
||||
/* re-schedule if sys write is NOT ready */
|
||||
schedule_delayed_work(&cpufreq_governor_daemon,
|
||||
msecs_to_jiffies(3000));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int __init imx_scu_switch_cpufreq_governor(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
INIT_DELAYED_WORK(&cpufreq_governor_daemon,
|
||||
cpufreq_governor_daemon_handler);
|
||||
|
||||
for (i = 1; i < num_online_cpus(); i++) {
|
||||
if (topology_physical_package_id(i) == topology_physical_package_id(0))
|
||||
continue;
|
||||
|
||||
schedule_delayed_work(&cpufreq_governor_daemon,
|
||||
msecs_to_jiffies(3000));
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
late_initcall(imx_scu_switch_cpufreq_governor);
|
||||
|
|
Loading…
Reference in New Issue