From 11f4d90145bbbf4fbab945af4fff3260108ddb4d Mon Sep 17 00:00:00 2001 From: Srinivas Rao L Date: Fri, 1 May 2015 10:54:33 +0530 Subject: [PATCH] soc: cpu_pwr_ctl: Add 8976 cpu retention ldo configure support Add support to configure the performance cluster cpu retention ldo voltage. This value needs to be configured when a core is coldbooted. The core will then be able to enter retention at the programmed retention voltage. Change-Id: Idf46c31edfb2be7ce364070baea5550048301a14 Signed-off-by: Srinivas Rao L --- .../bindings/arm/msm/cpu-ldo-ret-8976.txt | 21 +++++ drivers/soc/qcom/cpu_ops.c | 22 +++++- drivers/soc/qcom/cpu_pwr_ctl.c | 76 +++++++++++++++++++ include/soc/qcom/cpu_pwr_ctl.h | 5 ++ 4 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/arm/msm/cpu-ldo-ret-8976.txt diff --git a/Documentation/devicetree/bindings/arm/msm/cpu-ldo-ret-8976.txt b/Documentation/devicetree/bindings/arm/msm/cpu-ldo-ret-8976.txt new file mode 100644 index 000000000000..cda77a1150c0 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/cpu-ldo-ret-8976.txt @@ -0,0 +1,21 @@ +*8976 Perf-CPU LDO Retention Voltage Configuration + +This device is used to program the appropriate LDO voltage for 8976 Performance cluster CPU's from the pre-programmed register. + +Required properties: +- compatible: + Must be "qcom,8976-cpu-ldo-vref" +- reg: + The register holds the base address to LDO_BHS. Use this + register base to configure the LDO for all the cpus. +- qcom,ldo-vref-ret: + Value to which the ldo voltage reference needs to be + programmed. + Value to be used is encoded. 0x9 = 0.5V and 0x10 = 0.55V + +Example: + ldo0:ldo-vref@b086000 { + compatible = "qcom,8976-cpu-ldo-vref"; + reg = <0xb086000 0x40>, + qcom,ldo-vref-ret = <0x9>; + }; diff --git a/drivers/soc/qcom/cpu_ops.c b/drivers/soc/qcom/cpu_ops.c index 95548b9b5db3..5ff46bfbc030 100644 --- a/drivers/soc/qcom/cpu_ops.c +++ b/drivers/soc/qcom/cpu_ops.c @@ -126,6 +126,20 @@ static int __init msm_cpu_prepare(unsigned int cpu) return 0; } +static int __init msm8976_cpu_prepare(unsigned int cpu) +{ + int ret; + u32 mpidr = cpu_logical_map(cpu); + + if ((per_cpu(cold_boot_done, 0) == false) + && MPIDR_AFFINITY_LEVEL(mpidr, 1)) { + ret = msm8976_cpu_ldo_config(0); + if (ret) + return ret; + } + + return msm_cpu_prepare(cpu); +} static int __init msm8994_cpu_prepare(unsigned int cpu) { @@ -162,6 +176,7 @@ static int msm_cpu_boot(unsigned int cpu) static int msm8976_cpu_boot(unsigned int cpu) { int ret = 0; + u32 mpidr = cpu_logical_map(cpu); if (per_cpu(cold_boot_done, cpu) == false) { if (of_board_is_sim()) { @@ -173,6 +188,11 @@ static int msm8976_cpu_boot(unsigned int cpu) if (ret) return ret; } + if (MPIDR_AFFINITY_LEVEL(mpidr, 1)) { + ret = msm8976_cpu_ldo_config(cpu); + if (ret) + return ret; + } per_cpu(cold_boot_done, cpu) = true; } return secondary_pen_release(cpu); @@ -266,7 +286,7 @@ CPU_METHOD_OF_DECLARE(msm8994_cortex_a_ops, &msm8994_cortex_a_ops); static const struct cpu_operations msm8976_cortex_a_ops = { .name = "qcom,8976-arm-cortex-acc", .cpu_init = msm_cpu_init, - .cpu_prepare = msm_cpu_prepare, + .cpu_prepare = msm8976_cpu_prepare, .cpu_boot = msm8976_cpu_boot, .cpu_postboot = msm_cpu_postboot, #ifdef CONFIG_HOTPLUG_CPU diff --git a/drivers/soc/qcom/cpu_pwr_ctl.c b/drivers/soc/qcom/cpu_pwr_ctl.c index b2ed0bdd1e87..89bd7a73af1c 100644 --- a/drivers/soc/qcom/cpu_pwr_ctl.c +++ b/drivers/soc/qcom/cpu_pwr_ctl.c @@ -49,6 +49,7 @@ #define APC_LDO_CFG2 0x10 #define APC_LDO_VREF_CFG 0x4 #define APC_LDO_BHS_PWR_CTL 0x28 +#define APC_LDO_RDAC_CTL 0x34 /* * struct msm_l2ccc_of_info: represents of data for l2 cache clock controller. @@ -571,6 +572,81 @@ out_acc: return ret; } +int msm8976_cpu_ldo_config(unsigned int cpu) +{ + struct device_node *cpu_node, *ldo_node; + void __iomem *ldo_bhs_reg_base; + u32 ldo_vref_ret = 0; + u32 ref_val = 0; + int ret = 0; + u32 val; + + cpu_node = of_get_cpu_node(cpu, NULL); + if (!cpu_node) + return -ENODEV; + + ldo_node = of_parse_phandle(cpu_node, "qcom,ldo", 0); + if (!ldo_node) { + pr_debug("LDO is not configured to enable retention\n"); + goto exit_cpu_node; + } + + ldo_bhs_reg_base = of_iomap(ldo_node, 0); + if (!ldo_bhs_reg_base) { + pr_err("LDO configuration failed due to iomap failure\n"); + ret = -ENOMEM; + goto exit_cpu_node; + } + + ret = of_property_read_u32(ldo_node, "qcom,ldo-vref-ret", &ref_val); + if (ret) { + pr_err("Failed to get LDO Reference voltage for CPU%u\n", + cpu); + ret = -ENOENT; + goto exit_cpu_node; + } + + /* Bring LDO out of reset */ + ldo_vref_ret = readl_relaxed(ldo_bhs_reg_base + APC_LDO_VREF_CFG); + ldo_vref_ret &= ~BIT(16); + writel_relaxed(ldo_vref_ret, ldo_bhs_reg_base + APC_LDO_VREF_CFG); + + val = readl_relaxed(ldo_bhs_reg_base + APC_LDO_CFG1); + val = (val & 0xffffff00) | 0x90; + writel_relaxed(val, ldo_bhs_reg_base + APC_LDO_CFG1); + val = readl_relaxed(ldo_bhs_reg_base + APC_LDO_RDAC_CTL); + val = (val & 0xffffff00) | 0x60; + writel_relaxed(val, ldo_bhs_reg_base + APC_LDO_RDAC_CTL); + + /* Program the retention voltage */ + ldo_vref_ret = readl_relaxed(ldo_bhs_reg_base + APC_LDO_VREF_CFG); + ldo_vref_ret = (ldo_vref_ret & 0xffff80ff) | (ref_val << 8); + writel_relaxed(ldo_vref_ret, ldo_bhs_reg_base + APC_LDO_VREF_CFG); + + /* Write the sequence to latch on the LDO voltage */ + writel_relaxed(0x0, ldo_bhs_reg_base); + writel_relaxed(0x1, ldo_bhs_reg_base); + /* After writing 1 to the UPDATE register, '1 xo clk cycle' delay + * is required for the update to take effect. This delay needs to + * start after the reg write is complete. Make sure that the reg + * write is complete using a memory barrier */ + mb(); + usleep(1); + writel_relaxed(0x0, ldo_bhs_reg_base); + /* Use a memory barrier to make sure the reg write is complete before + * the node is unmapped. */ + mb(); + + of_node_put(ldo_node); + + iounmap(ldo_bhs_reg_base); + +exit_cpu_node: + of_node_put(cpu_node); + + return ret; +} + static inline void msm8976_unclamp_perf_cluster_cpu(void __iomem *reg) { diff --git a/include/soc/qcom/cpu_pwr_ctl.h b/include/soc/qcom/cpu_pwr_ctl.h index 1f67b39e4caf..6d09f528c174 100644 --- a/include/soc/qcom/cpu_pwr_ctl.h +++ b/include/soc/qcom/cpu_pwr_ctl.h @@ -19,6 +19,7 @@ int msm_unclamp_secondary_arm_cpu(unsigned int cpu); int msm8994_unclamp_secondary_arm_cpu(unsigned int cpu); int msm8976_unclamp_secondary_arm_cpu(unsigned int cpu); int msm8994_cpu_ldo_config(unsigned int cpu); +int msm8976_cpu_ldo_config(unsigned int cpu); #else static inline int msm_unclamp_secondary_arm_cpu_sim(unsigned int cpu) { @@ -40,5 +41,9 @@ static inline int msm8994_cpu_ldo_config(unsigned int cpu) { return 0; } +static inline int msm8976_cpu_ldo_config(unsigned int cpu) +{ + return 0; +} #endif #endif /*MSM_CPU_SUBSYS_H_*/