summaryrefslogtreecommitdiff
path: root/arch/powerpc/sysdev/fsl_rcpm.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/sysdev/fsl_rcpm.c')
-rw-r--r--arch/powerpc/sysdev/fsl_rcpm.c114
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[] = {