From: Rohit Vaswani <rvasw...@codeaurora.org>

Implement support for the Krait CPU release sequence when the
CPUs are part of the second version of the Krait processor
subsystem.

Signed-off-by: Rohit Vaswani <rvasw...@codeaurora.org>
Signed-off-by: Stephen Boyd <sb...@codeaurora.org>
---
 arch/arm/mach-msm/platsmp.c | 123 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 123 insertions(+)

diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 4b13cd8..f07ad9d 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -38,7 +38,15 @@
 #define L2DT_SLP               BIT(3)
 #define CLAMP                  BIT(0)
 
+#define APC_PWR_GATE_CTL       0x14
+#define BHS_CNT_SHIFT          24
+#define LDO_PWR_DWN_SHIFT      16
+#define LDO_BYP_SHIFT          8
+#define BHS_SEG_SHIFT          1
+#define BHS_EN                 BIT(0)
+
 #define APCS_SAW2_VCTL         0x14
+#define APCS_SAW2_2_VCTL       0x1c
 
 extern void secondary_startup(void);
 
@@ -157,6 +165,106 @@ out_acc:
        return ret;
 }
 
+static int kpssv2_release_secondary(unsigned int cpu)
+{
+       void __iomem *reg;
+       struct device_node *cpu_node, *l2_node, *acc_node, *saw_node;
+       void __iomem *l2_saw_base;
+       unsigned reg_val;
+       int ret;
+
+       cpu_node = of_get_cpu_node(cpu, NULL);
+       if (!cpu_node)
+               return -ENODEV;
+
+       acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0);
+       if (!acc_node) {
+               ret = -ENODEV;
+               goto out_acc;
+       }
+
+       l2_node = of_parse_phandle(cpu_node, "next-level-cache", 0);
+       if (!l2_node) {
+               ret = -ENODEV;
+               goto out_l2;
+       }
+
+       saw_node = of_parse_phandle(l2_node, "qcom,saw", 0);
+       if (!saw_node) {
+               ret = -ENODEV;
+               goto out_saw;
+       }
+
+       reg = of_iomap(acc_node, 0);
+       if (!reg) {
+               ret = -ENOMEM;
+               goto out_map;
+       }
+
+       l2_saw_base = of_iomap(saw_node, 0);
+       if (!l2_saw_base) {
+               ret = -ENOMEM;
+               goto out_saw_map;
+       }
+
+       /* Turn on the BHS, turn off LDO Bypass and power down LDO */
+       reg_val = (64 << BHS_CNT_SHIFT) | (0x3f << LDO_PWR_DWN_SHIFT) | BHS_EN;
+       writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
+       mb();
+       /* wait for the BHS to settle */
+       udelay(1);
+
+       /* Turn on BHS segments */
+       reg_val |= 0x3f << BHS_SEG_SHIFT;
+       writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
+       mb();
+        /* wait for the BHS to settle */
+       udelay(1);
+
+       /* Finally turn on the bypass so that BHS supplies power */
+       reg_val |= 0x3f << LDO_BYP_SHIFT;
+       writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
+
+       /* enable max phases */
+       writel_relaxed(0x10003, l2_saw_base + APCS_SAW2_2_VCTL);
+       mb();
+       udelay(50);
+
+       reg_val = COREPOR_RST | CLAMP;
+       writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
+       mb();
+       udelay(2);
+
+       reg_val &= ~CLAMP;
+       writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
+       mb();
+       udelay(2);
+
+       reg_val &= ~COREPOR_RST;
+       writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
+       mb();
+
+       reg_val |= CORE_PWRD_UP;
+       writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
+       mb();
+
+       ret = 0;
+
+       iounmap(l2_saw_base);
+out_saw_map:
+       iounmap(reg);
+out_map:
+       of_node_put(saw_node);
+out_saw:
+       of_node_put(l2_node);
+out_l2:
+       of_node_put(acc_node);
+out_acc:
+       of_node_put(cpu_node);
+
+       return ret;
+}
+
 static DEFINE_PER_CPU(int, cold_boot_done);
 
 static int msm_boot_secondary(unsigned int cpu, int (*func)(unsigned int))
@@ -201,6 +309,11 @@ static int kpssv1_boot_secondary(unsigned int cpu, struct 
task_struct *idle)
        return msm_boot_secondary(cpu, kpssv1_release_secondary);
 }
 
+static int kpssv2_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+       return msm_boot_secondary(cpu, kpssv2_release_secondary);
+}
+
 static void __init msm_smp_prepare_cpus(unsigned int max_cpus)
 {
        int cpu, map;
@@ -250,3 +363,13 @@ static struct smp_operations msm_smp_kpssv1_ops __initdata 
= {
 #endif
 };
 CPU_METHOD_OF_DECLARE(msm_smp_kpssv1, "qcom,kpss-acc-v1", &msm_smp_kpssv1_ops);
+
+static struct smp_operations msm_smp_kpssv2_ops __initdata = {
+       .smp_prepare_cpus       = msm_smp_prepare_cpus,
+       .smp_secondary_init     = msm_secondary_init,
+       .smp_boot_secondary     = kpssv2_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+       .cpu_die                = msm_cpu_die,
+#endif
+};
+CPU_METHOD_OF_DECLARE(msm_smp_kpssv2, "qcom,kpss-acc-v2", &msm_smp_kpssv2_ops);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to