diff options
Diffstat (limited to 'arch/powerpc/sysdev/fsl_rcpm.c')
-rw-r--r-- | arch/powerpc/sysdev/fsl_rcpm.c | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/arch/powerpc/sysdev/fsl_rcpm.c b/arch/powerpc/sysdev/fsl_rcpm.c index 6b26678..8b8befb 100644 --- a/arch/powerpc/sysdev/fsl_rcpm.c +++ b/arch/powerpc/sysdev/fsl_rcpm.c @@ -21,6 +21,8 @@ #include <asm/fsl_pm.h> #include <asm/machdep.h> +#include <platforms/85xx/smp.h> + const struct fsl_pm_ops *qoriq_pm_ops; static struct ccsr_rcpm_v1 __iomem *rcpm_v1_regs; @@ -240,6 +242,46 @@ static void rcpm_v2_cpu_exit_state(int cpu, int state) } } +static void rcpm_v2_cluster_enter_state(int cpu, int state) +{ + u32 cpu_on_cluster, cluster_mask; + const struct cpumask *cpumask; + + cpumask = cpu_cluster_mask(cpu); + cpu_on_cluster = cpu / cpumask_weight(cpumask); + cluster_mask = 1 << cpu_on_cluster; + + switch (state) { + case E500_PM_PCL10: + /* one bit corresponds to one cluster */ + out_be32(&rcpm_v2_regs->clpcl10setr, cluster_mask); + + break; + default: + pr_err("%s: Unknown cluster PM state (%d)\n", __func__, state); + } +} + +static void rcpm_v2_cluster_exit_state(int cpu, int state) +{ + u32 cpu_on_cluster, cluster_mask; + const struct cpumask *cpumask; + + cpumask = cpu_cluster_mask(cpu); + cpu_on_cluster = cpu / cpumask_weight(cpumask); + cluster_mask = 1 << cpu_on_cluster; + + switch (state) { + case E500_PM_PCL10: + /* one bit corresponds to one cluster */ + out_be32(&rcpm_v2_regs->clpcl10clrr, cluster_mask); + break; + default: + pr_err("%s: Unknown cluster PM state (%d)\n", __func__, state); + } +} + + static int rcpm_v2_plat_enter_state(int state) { u32 *pmcsr_reg = &rcpm_v2_regs->powmgtcsr; @@ -273,6 +315,75 @@ static int rcpm_v2_plat_enter_state(int state) return ret; } +bool rcpm_v2_cpu_ready(unsigned int cpu, int state) +{ + unsigned int hw_cpu; + u32 mask; + bool ret = false; + const struct cpumask *cluster_mask; + u32 cpu_on_cluster = 0; + int tmp_cpu = 0; + + hw_cpu = get_hard_smp_processor_id(cpu); + + switch (state) { + case E500_PM_PH10: + if (in_be32(&rcpm_v2_regs->tph10sr0) & (1 << hw_cpu)) + ret = true; + break; + case E500_PM_PW10: + if (in_be32(&rcpm_v2_regs->twaitsr0) & (1 << hw_cpu)) + ret = true; + break; + case E500_PM_PH15: + mask = 1 << cpu_core_index_of_thread(hw_cpu); + + if (in_be32(&rcpm_v2_regs->pcph15sr) & mask) + ret = true; + break; + case E500_PM_PH20: + mask = 1 << cpu_core_index_of_thread(hw_cpu); + + if (in_be32(&rcpm_v2_regs->pcph20sr) & mask) + ret = true; + break; + case E500_PM_PW20: + mask = 1 << cpu_core_index_of_thread(hw_cpu); + + if (in_be32(&rcpm_v2_regs->pcpw20sr) & mask) + ret = true; + break; + case E500_PM_PH30: + mask = 1 << cpu_core_index_of_thread(hw_cpu); + + if (in_be32(&rcpm_v2_regs->pcph30sr) & mask) + ret = true; + break; + case E500_PM_PCL10: + cluster_mask = cpu_cluster_mask(boot_cpuid); + tmp_cpu += cpumask_weight(cluster_mask); + + while (cpu >= tmp_cpu) { + cpu_on_cluster++; + cluster_mask = cpu_cluster_mask(tmp_cpu); + tmp_cpu += cpumask_weight(cluster_mask); + } + + mask = 1 << cpu_on_cluster; + + if (in_be32(&rcpm_v2_regs->clpcl10sr) & mask) + ret = true; + break; + default: + pr_err("%s: Unknown platform PM state (%d)\n", + __func__, state); + ret = false; + + } + + return ret; +} + static const struct fsl_pm_ops qoriq_rcpm_v1_ops = { .irq_mask = rcpm_v1_irq_mask, .irq_unmask = rcpm_v1_irq_unmask, @@ -288,9 +399,12 @@ static const struct fsl_pm_ops qoriq_rcpm_v2_ops = { .irq_unmask = rcpm_v2_irq_unmask, .cpu_enter_state = rcpm_v2_cpu_enter_state, .cpu_exit_state = rcpm_v2_cpu_exit_state, + .cluster_enter_state = rcpm_v2_cluster_enter_state, + .cluster_exit_state = rcpm_v2_cluster_exit_state, .plat_enter_state = rcpm_v2_plat_enter_state, .set_ip_power = rcpm_v2_set_ip_power, .freeze_time_base = rcpm_v2_freeze_time_base, + .cpu_ready = rcpm_v2_cpu_ready, }; static const struct of_device_id rcpm_matches[] = { |