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 <lsrao@codeaurora.org>
This commit is contained in:
Srinivas Rao L 2015-05-01 10:54:33 +05:30
parent 5e453077d2
commit 11f4d90145
4 changed files with 123 additions and 1 deletions

View File

@ -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>;
};

View File

@ -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

View File

@ -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)
{

View File

@ -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_*/