Loading Documentation/devicetree/bindings/arm/cpus.txt +1 −0 Original line number Diff line number Diff line Loading @@ -185,6 +185,7 @@ nodes to be present and contain the properties described below. be one of: "psci" "spin-table" "qcom,titanium-arm-cortex-acc" # On ARM 32-bit systems this property is optional and can be one of: Loading Documentation/devicetree/bindings/arm/msm/l2ccc.txt +1 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ region per CPU Cluster. Required properties: - compatible: Can be one of: "qcom,8916-l2ccc" "qcom,titanium-l2ccc" - reg: This specifies the base address and size of the register region. Loading drivers/soc/qcom/cpu_ops.c +48 −0 Original line number Diff line number Diff line Loading @@ -126,6 +126,38 @@ static int __init msm_cpu_prepare(unsigned int cpu) return 0; } static int msmtitanium_cpu_boot(unsigned int cpu) { int ret = 0; if (per_cpu(cold_boot_done, cpu) == false) { ret = msmtitanium_unclamp_secondary_arm_cpu(cpu); if (ret) return ret; per_cpu(cold_boot_done, cpu) = true; } return secondary_pen_release(cpu); } #ifdef CONFIG_HOTPLUG_CPU static void msmtitanium_wfi_cpu_die(unsigned int cpu) { if (unlikely(cpu != smp_processor_id())) { pr_crit("%s: running on %u, should be %u\n", __func__, smp_processor_id(), cpu); BUG(); } for (;;) { wfi(); if (secondary_holding_pen_release == cpu_logical_map(cpu)) break; /*Proper wake up */ pr_debug("CPU%u: spurious wakeup call\n", cpu); BUG(); } } #endif static int msm_cpu_boot(unsigned int cpu) { Loading Loading @@ -196,3 +228,19 @@ static struct cpu_operations msm_cortex_a_ops = { }; CPU_METHOD_OF_DECLARE(msm_cortex_a_ops, "qcom,arm-cortex-acc", &msm_cortex_a_ops); static struct cpu_operations msmtitanium_cortex_a_ops = { .name = "qcom,titanium-arm-cortex-acc", .cpu_init = msm_cpu_init, .cpu_prepare = msm_cpu_prepare, .cpu_boot = msmtitanium_cpu_boot, .cpu_postboot = msm_cpu_postboot, #ifdef CONFIG_HOTPLUG_CPU .cpu_die = msmtitanium_wfi_cpu_die, #endif #ifdef CONFIG_ARM64_CPU_SUSPEND .cpu_suspend = msm_pm_collapse, #endif }; CPU_METHOD_OF_DECLARE(msmtitanium_cortex_a_ops, "qcom,titanium-arm-cortex-acc", &msmtitanium_cortex_a_ops); drivers/soc/qcom/cpu_pwr_ctl.c +200 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <asm/barrier.h> #include <asm/cacheflush.h> #include <asm/smp_plat.h> /* CPU power domain register offsets */ #define CPU_PWR_CTL 0x4 Loading @@ -52,6 +53,90 @@ struct msm_l2ccc_of_info { }; static int power_on_l2_msmtitanium(struct device_node *l2ccc_node, u32 pon_mask, int cpu) { u32 pon_status; void __iomem *l2_base; l2_base = of_iomap(l2ccc_node, 0); if (!l2_base) return -ENOMEM; /* Skip power-on sequence if l2 cache is already powered up */ pon_status = (__raw_readl(l2_base + L2_PWR_STATUS) & pon_mask) == pon_mask; if (pon_status) { iounmap(l2_base); return 0; } /* Close Few of the head-switches for L2SCU logic */ writel_relaxed(0x10F700, l2_base + L2_PWR_CTL); mb(); udelay(2); /* Close Rest of the head-switches for L2SCU logic */ writel_relaxed(0x410F700, l2_base + L2_PWR_CTL); mb(); udelay(2); /* Assert PRESETDBG */ writel_relaxed(0x400000, l2_base + L2_PWR_CTL_OVERRIDE); mb(); udelay(2); /* De-assert L2/SCU memory Clamp */ writel_relaxed(0x4103700, l2_base + L2_PWR_CTL); mb(); /* Assert L2 memory slp_nret_n */ writel_relaxed(0x4103703, l2_base + L2_PWR_CTL); mb(); udelay(4); /* Assert L2 memory slp_ret_n */ writel_relaxed(0x4101703, l2_base + L2_PWR_CTL); mb(); udelay(4); /* Assert L2 memory wl_en_clk */ writel_relaxed(0x4101783, l2_base + L2_PWR_CTL); mb(); udelay(1); /* De-assert L2 memory wl_en_clk */ writel_relaxed(0x4101703, l2_base + L2_PWR_CTL); mb(); /* Enable clocks via SW_CLK_EN */ writel_relaxed(0x01, l2_base + L2_CORE_CBCR); mb(); /* De-assert L2/SCU logic clamp */ writel_relaxed(0x4101603, l2_base + L2_PWR_CTL); mb(); udelay(2); /* De-assert PRESETDBG */ writel_relaxed(0x0, l2_base + L2_PWR_CTL_OVERRIDE); mb(); /* De-assert L2/SCU Logic reset */ writel_relaxed(0x4100203, l2_base + L2_PWR_CTL); mb(); udelay(54); /* Turn on the PMIC_APC */ writel_relaxed(0x14100203, l2_base + L2_PWR_CTL); mb(); /* Set H/W clock control for the cluster CBC block */ writel_relaxed(0x03, l2_base + L2_CORE_CBCR); mb(); iounmap(l2_base); return 0; } static int power_on_l2_msm8916(struct device_node *l2ccc_node, u32 pon_mask, int cpu) { Loading Loading @@ -119,6 +204,11 @@ static const struct msm_l2ccc_of_info l2ccc_info[] = { .l2_power_on = power_on_l2_msm8916, .l2_power_on_mask = BIT(9), }, { .compat = "qcom,titanium-l2ccc", .l2_power_on = power_on_l2_msmtitanium, .l2_power_on_mask = BIT(9) | BIT(28), }, }; static int power_on_l2_cache(struct device_node *l2ccc_node, int cpu) Loading @@ -141,6 +231,116 @@ static int power_on_l2_cache(struct device_node *l2ccc_node, int cpu) return -EIO; } static inline void msmtitanium_unclamp_cpu(void __iomem *reg) { /* Deassert CPU in sleep state */ writel_relaxed(0x00000033, reg + CPU_PWR_CTL); mb(); /* Program skew between en_few and en_rest to 16 XO clk cycles, close Core logic head switch*/ writel_relaxed(0x10000001, reg + CPU_PWR_GATE_CTL); mb(); udelay(2); /* De-assert coremem clamp */ writel_relaxed(0x00000031, reg + CPU_PWR_CTL); mb(); /* De-assert Core memory slp_nret_n */ writel_relaxed(0x00000039, reg + CPU_PWR_CTL); mb(); udelay(2); /* De-assert Core memory slp_ret_n */ writel_relaxed(0x00000239, reg + CPU_PWR_CTL); mb(); udelay(2); /* Assert WL_EN_CLK */ writel_relaxed(0x00004239, reg + CPU_PWR_CTL); mb(); udelay(2); /* De-assert WL_EN_CLK */ writel_relaxed(0x00000239, reg + CPU_PWR_CTL); mb(); /* Deassert Clamp */ writel_relaxed(0x00000238, reg + CPU_PWR_CTL); mb(); udelay(2); /* Deassert Core-n reset */ writel_relaxed(0x00000208, reg + CPU_PWR_CTL); mb(); /* Assert PWRDUP; */ writel_relaxed(0x00000288, reg + CPU_PWR_CTL); mb(); } int msmtitanium_unclamp_secondary_arm_cpu(unsigned int cpu) { int ret = 0; struct device_node *cpu_node, *acc_node, *l2_node, *l2ccc_node; void __iomem *reg; 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; } l2ccc_node = of_parse_phandle(l2_node, "power-domain", 0); if (!l2ccc_node) { ret = -ENODEV; goto out_l2ccc; } /* * Ensure L2-cache of the CPU is powered on before * unclamping cpu power rails. */ ret = power_on_l2_cache(l2ccc_node, cpu); if (ret) { pr_err("L2 cache power up failed for CPU%d\n", cpu); goto out_acc_reg; } reg = of_iomap(acc_node, 0); if (!reg) { ret = -ENOMEM; goto out_acc_reg; } msmtitanium_unclamp_cpu(reg); /* Secondary CPU-N is now alive */ iounmap(reg); out_acc_reg: of_node_put(l2ccc_node); out_l2ccc: of_node_put(l2_node); out_l2: of_node_put(acc_node); out_acc: of_node_put(cpu_node); return ret; } int msm_unclamp_secondary_arm_cpu(unsigned int cpu) { Loading include/soc/qcom/cpu_pwr_ctl.h +5 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #ifdef CONFIG_MSM_CPU_PWR_CTL int msm_unclamp_secondary_arm_cpu_sim(unsigned int cpu); int msm_unclamp_secondary_arm_cpu(unsigned int cpu); int msmtitanium_unclamp_secondary_arm_cpu(unsigned int cpu); #else static inline int msm_unclamp_secondary_arm_cpu_sim(unsigned int cpu) { Loading @@ -25,5 +26,9 @@ static inline int msm_unclamp_secondary_arm_cpu(unsigned int cpu) { return 0; } static inline int msmtitanium_unclamp_secondary_arm_cpu(unsigned int cpu) { return 0; } #endif #endif /*MSM_CPU_SUBSYS_H_*/ Loading
Documentation/devicetree/bindings/arm/cpus.txt +1 −0 Original line number Diff line number Diff line Loading @@ -185,6 +185,7 @@ nodes to be present and contain the properties described below. be one of: "psci" "spin-table" "qcom,titanium-arm-cortex-acc" # On ARM 32-bit systems this property is optional and can be one of: Loading
Documentation/devicetree/bindings/arm/msm/l2ccc.txt +1 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ region per CPU Cluster. Required properties: - compatible: Can be one of: "qcom,8916-l2ccc" "qcom,titanium-l2ccc" - reg: This specifies the base address and size of the register region. Loading
drivers/soc/qcom/cpu_ops.c +48 −0 Original line number Diff line number Diff line Loading @@ -126,6 +126,38 @@ static int __init msm_cpu_prepare(unsigned int cpu) return 0; } static int msmtitanium_cpu_boot(unsigned int cpu) { int ret = 0; if (per_cpu(cold_boot_done, cpu) == false) { ret = msmtitanium_unclamp_secondary_arm_cpu(cpu); if (ret) return ret; per_cpu(cold_boot_done, cpu) = true; } return secondary_pen_release(cpu); } #ifdef CONFIG_HOTPLUG_CPU static void msmtitanium_wfi_cpu_die(unsigned int cpu) { if (unlikely(cpu != smp_processor_id())) { pr_crit("%s: running on %u, should be %u\n", __func__, smp_processor_id(), cpu); BUG(); } for (;;) { wfi(); if (secondary_holding_pen_release == cpu_logical_map(cpu)) break; /*Proper wake up */ pr_debug("CPU%u: spurious wakeup call\n", cpu); BUG(); } } #endif static int msm_cpu_boot(unsigned int cpu) { Loading Loading @@ -196,3 +228,19 @@ static struct cpu_operations msm_cortex_a_ops = { }; CPU_METHOD_OF_DECLARE(msm_cortex_a_ops, "qcom,arm-cortex-acc", &msm_cortex_a_ops); static struct cpu_operations msmtitanium_cortex_a_ops = { .name = "qcom,titanium-arm-cortex-acc", .cpu_init = msm_cpu_init, .cpu_prepare = msm_cpu_prepare, .cpu_boot = msmtitanium_cpu_boot, .cpu_postboot = msm_cpu_postboot, #ifdef CONFIG_HOTPLUG_CPU .cpu_die = msmtitanium_wfi_cpu_die, #endif #ifdef CONFIG_ARM64_CPU_SUSPEND .cpu_suspend = msm_pm_collapse, #endif }; CPU_METHOD_OF_DECLARE(msmtitanium_cortex_a_ops, "qcom,titanium-arm-cortex-acc", &msmtitanium_cortex_a_ops);
drivers/soc/qcom/cpu_pwr_ctl.c +200 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <asm/barrier.h> #include <asm/cacheflush.h> #include <asm/smp_plat.h> /* CPU power domain register offsets */ #define CPU_PWR_CTL 0x4 Loading @@ -52,6 +53,90 @@ struct msm_l2ccc_of_info { }; static int power_on_l2_msmtitanium(struct device_node *l2ccc_node, u32 pon_mask, int cpu) { u32 pon_status; void __iomem *l2_base; l2_base = of_iomap(l2ccc_node, 0); if (!l2_base) return -ENOMEM; /* Skip power-on sequence if l2 cache is already powered up */ pon_status = (__raw_readl(l2_base + L2_PWR_STATUS) & pon_mask) == pon_mask; if (pon_status) { iounmap(l2_base); return 0; } /* Close Few of the head-switches for L2SCU logic */ writel_relaxed(0x10F700, l2_base + L2_PWR_CTL); mb(); udelay(2); /* Close Rest of the head-switches for L2SCU logic */ writel_relaxed(0x410F700, l2_base + L2_PWR_CTL); mb(); udelay(2); /* Assert PRESETDBG */ writel_relaxed(0x400000, l2_base + L2_PWR_CTL_OVERRIDE); mb(); udelay(2); /* De-assert L2/SCU memory Clamp */ writel_relaxed(0x4103700, l2_base + L2_PWR_CTL); mb(); /* Assert L2 memory slp_nret_n */ writel_relaxed(0x4103703, l2_base + L2_PWR_CTL); mb(); udelay(4); /* Assert L2 memory slp_ret_n */ writel_relaxed(0x4101703, l2_base + L2_PWR_CTL); mb(); udelay(4); /* Assert L2 memory wl_en_clk */ writel_relaxed(0x4101783, l2_base + L2_PWR_CTL); mb(); udelay(1); /* De-assert L2 memory wl_en_clk */ writel_relaxed(0x4101703, l2_base + L2_PWR_CTL); mb(); /* Enable clocks via SW_CLK_EN */ writel_relaxed(0x01, l2_base + L2_CORE_CBCR); mb(); /* De-assert L2/SCU logic clamp */ writel_relaxed(0x4101603, l2_base + L2_PWR_CTL); mb(); udelay(2); /* De-assert PRESETDBG */ writel_relaxed(0x0, l2_base + L2_PWR_CTL_OVERRIDE); mb(); /* De-assert L2/SCU Logic reset */ writel_relaxed(0x4100203, l2_base + L2_PWR_CTL); mb(); udelay(54); /* Turn on the PMIC_APC */ writel_relaxed(0x14100203, l2_base + L2_PWR_CTL); mb(); /* Set H/W clock control for the cluster CBC block */ writel_relaxed(0x03, l2_base + L2_CORE_CBCR); mb(); iounmap(l2_base); return 0; } static int power_on_l2_msm8916(struct device_node *l2ccc_node, u32 pon_mask, int cpu) { Loading Loading @@ -119,6 +204,11 @@ static const struct msm_l2ccc_of_info l2ccc_info[] = { .l2_power_on = power_on_l2_msm8916, .l2_power_on_mask = BIT(9), }, { .compat = "qcom,titanium-l2ccc", .l2_power_on = power_on_l2_msmtitanium, .l2_power_on_mask = BIT(9) | BIT(28), }, }; static int power_on_l2_cache(struct device_node *l2ccc_node, int cpu) Loading @@ -141,6 +231,116 @@ static int power_on_l2_cache(struct device_node *l2ccc_node, int cpu) return -EIO; } static inline void msmtitanium_unclamp_cpu(void __iomem *reg) { /* Deassert CPU in sleep state */ writel_relaxed(0x00000033, reg + CPU_PWR_CTL); mb(); /* Program skew between en_few and en_rest to 16 XO clk cycles, close Core logic head switch*/ writel_relaxed(0x10000001, reg + CPU_PWR_GATE_CTL); mb(); udelay(2); /* De-assert coremem clamp */ writel_relaxed(0x00000031, reg + CPU_PWR_CTL); mb(); /* De-assert Core memory slp_nret_n */ writel_relaxed(0x00000039, reg + CPU_PWR_CTL); mb(); udelay(2); /* De-assert Core memory slp_ret_n */ writel_relaxed(0x00000239, reg + CPU_PWR_CTL); mb(); udelay(2); /* Assert WL_EN_CLK */ writel_relaxed(0x00004239, reg + CPU_PWR_CTL); mb(); udelay(2); /* De-assert WL_EN_CLK */ writel_relaxed(0x00000239, reg + CPU_PWR_CTL); mb(); /* Deassert Clamp */ writel_relaxed(0x00000238, reg + CPU_PWR_CTL); mb(); udelay(2); /* Deassert Core-n reset */ writel_relaxed(0x00000208, reg + CPU_PWR_CTL); mb(); /* Assert PWRDUP; */ writel_relaxed(0x00000288, reg + CPU_PWR_CTL); mb(); } int msmtitanium_unclamp_secondary_arm_cpu(unsigned int cpu) { int ret = 0; struct device_node *cpu_node, *acc_node, *l2_node, *l2ccc_node; void __iomem *reg; 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; } l2ccc_node = of_parse_phandle(l2_node, "power-domain", 0); if (!l2ccc_node) { ret = -ENODEV; goto out_l2ccc; } /* * Ensure L2-cache of the CPU is powered on before * unclamping cpu power rails. */ ret = power_on_l2_cache(l2ccc_node, cpu); if (ret) { pr_err("L2 cache power up failed for CPU%d\n", cpu); goto out_acc_reg; } reg = of_iomap(acc_node, 0); if (!reg) { ret = -ENOMEM; goto out_acc_reg; } msmtitanium_unclamp_cpu(reg); /* Secondary CPU-N is now alive */ iounmap(reg); out_acc_reg: of_node_put(l2ccc_node); out_l2ccc: of_node_put(l2_node); out_l2: of_node_put(acc_node); out_acc: of_node_put(cpu_node); return ret; } int msm_unclamp_secondary_arm_cpu(unsigned int cpu) { Loading
include/soc/qcom/cpu_pwr_ctl.h +5 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #ifdef CONFIG_MSM_CPU_PWR_CTL int msm_unclamp_secondary_arm_cpu_sim(unsigned int cpu); int msm_unclamp_secondary_arm_cpu(unsigned int cpu); int msmtitanium_unclamp_secondary_arm_cpu(unsigned int cpu); #else static inline int msm_unclamp_secondary_arm_cpu_sim(unsigned int cpu) { Loading @@ -25,5 +26,9 @@ static inline int msm_unclamp_secondary_arm_cpu(unsigned int cpu) { return 0; } static inline int msmtitanium_unclamp_secondary_arm_cpu(unsigned int cpu) { return 0; } #endif #endif /*MSM_CPU_SUBSYS_H_*/