msm: cpr: Enable CPR support for 8625
CPR (Core Power Reduction) helps save CPU power by
reducing the chip voltage whenever possible
Change-Id: Ifa32967046b4bb7f5b4f756feb9cefabe8f5bea4
Signed-off-by: Kaushal Kumar <kaushalk@codeaurora.org>
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 1fcf7dc..93fd12d 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -39,6 +39,8 @@
#include "mpm-8625.h"
#include "irq.h"
#include "pm.h"
+#include "msm_cpr.h"
+#include "msm_smem_iface.h"
/* Address of GSBI blocks */
#define MSM_GSBI0_PHYS 0xA1200000
@@ -48,6 +50,12 @@
#define MSM_GSBI0_QUP_PHYS (MSM_GSBI0_PHYS + 0x80000)
#define MSM_GSBI1_QUP_PHYS (MSM_GSBI1_PHYS + 0x80000)
+#define A11S_TEST_BUS_SEL_ADDR (MSM_CSR_BASE + 0x518)
+#define RBCPR_CLK_MUX_SEL (1 << 13)
+
+/* Reset Address of RBCPR (Active Low)*/
+#define RBCPR_SW_RESET_N (MSM_CSR_BASE + 0x64)
+
static struct resource gsbi0_qup_i2c_resources[] = {
{
.name = "qup_phys_addr",
@@ -1579,6 +1587,176 @@
},
};
+static struct resource cpr_resources[] = {
+ {
+ .start = MSM8625_INT_CPR_IRQ0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MSM8625_CPR_PHYS,
+ .end = MSM8625_CPR_PHYS + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+/**
+ * These are various Vdd levels supported by PMIC
+ */
+static uint32_t msm_c2_pmic_mv[] __initdata = {
+ 1300, 12875 / 10, 1275, 12625 / 10, 1250,
+ 12375 / 10, 1225, 12125 / 10, 1200, 11875 / 10,
+ 1175, 11625 / 10, 1150, 11375 / 10, 1125,
+ 11125 / 10, 1100, 10875 / 10, 1075, 10625 / 10,
+ 1050, 10375 / 10, 1025, 10125 / 10, 0, 0, 0, 0,
+ 0, 0, 0, 1000,
+};
+
+/**
+ * This data will be based on CPR mode of operation
+ */
+static struct msm_cpr_mode msm_cpr_mode_data[] = {
+ [NORMAL_MODE] = {
+ .ring_osc_data = {
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ },
+ .ring_osc = 0,
+ .step_quot = ~0,
+ .tgt_volt_offset = 1,
+ .Vmax = 1200,
+ .Vmin = 1000,
+ .calibrated_mV = 1100,
+ },
+ [TURBO_MODE] = {
+ .ring_osc_data = {
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ },
+ .ring_osc = 0,
+ .step_quot = ~0,
+ .tgt_volt_offset = 1,
+ .Vmax = 1350,
+ .Vmin = 1250,
+ .calibrated_mV = 1300,
+ },
+};
+
+struct msm_cpr_vp_data vp_data = {
+ .min_volt = 1000,
+ .max_volt = 1350,
+ .default_volt = 1300,
+ .step_size = (12500 / 1000),
+};
+
+static struct msm_cpr_config msm_cpr_pdata = {
+ .ref_clk_khz = 19200,
+ .delay_us = 10000,
+ .irq_line = 0,
+ .cpr_mode_data = msm_cpr_mode_data,
+ .tgt_count_div_N = 1,
+ .floor = 0,
+ .ceiling = 40,
+ .sw_vlevel = 20,
+ .up_threshold = 1,
+ .dn_threshold = 2,
+ .up_margin = 0,
+ .dn_margin = 0,
+ .nom_freq_limit = 1008000,
+ .vp_data = &vp_data,
+};
+
+static struct platform_device msm8625_device_cpr = {
+ .name = "msm-cpr",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(cpr_resources),
+ .resource = cpr_resources,
+ .dev = {
+ .platform_data = &msm_cpr_pdata,
+ },
+};
+
+static struct platform_device msm8625_vp_device = {
+ .name = "vp-regulator",
+ .id = -1,
+};
+
+static void __init msm_cpr_init(void)
+{
+ struct cpr_info_type *cpr_info = NULL;
+ uint8_t ring_osc = 0;
+ uint32_t reg_val;
+
+ cpr_info = kzalloc(sizeof(struct cpr_info_type), GFP_KERNEL);
+ if (!cpr_info) {
+ pr_err("%s: Out of memory %d\n", __func__, -ENOMEM);
+ return;
+ }
+
+ msm_smem_get_cpr_info(cpr_info);
+
+ /**
+ * Set the ring_osc based on efuse BIT(0)
+ * CPR_fuse[0] = 0 selects 2nd RO (010)
+ * CPR_fuse[0] = 1 select 3rd RO (011)
+ */
+ if (cpr_info->ring_osc == 0x0)
+ ring_osc = 0x2;
+ else if (cpr_info->ring_osc == 0x1)
+ ring_osc = 0x3;
+
+ msm_cpr_mode_data[TURBO_MODE].ring_osc = ring_osc;
+ msm_cpr_mode_data[NORMAL_MODE].ring_osc = ring_osc;
+
+ /* GCNT = 1000 nsec/52nsec (@TCX0=19.2Mhz) = 19.2 */
+ msm_cpr_mode_data[TURBO_MODE].ring_osc_data[ring_osc].gcnt = 19;
+ msm_cpr_mode_data[NORMAL_MODE].ring_osc_data[ring_osc].gcnt = 19;
+
+ /* The multiplier and offset are as per PTE data */
+ msm_cpr_mode_data[TURBO_MODE].ring_osc_data[ring_osc].target_count =
+ cpr_info->turbo_quot * 10 + 440;
+ msm_cpr_mode_data[NORMAL_MODE].ring_osc_data[ring_osc].target_count =
+ cpr_info->turbo_quot / msm_cpr_pdata.tgt_count_div_N;
+
+ /**
+ * Bits 4:0 of pvs_fuse provide mapping to the safe boot up voltage.
+ * Boot up mode is by default Turbo.
+ */
+ msm_cpr_mode_data[TURBO_MODE].calibrated_mV =
+ msm_c2_pmic_mv[cpr_info->pvs_fuse & 0x1F];
+
+ /* TODO: Store the tgt_volt_offset values for the modes from PTE */
+
+
+ pr_debug("%s: cpr: ring_osc: 0x%x\n", __func__,
+ msm_cpr_mode_data[TURBO_MODE].ring_osc);
+ pr_debug("%s: cpr: turbo_quot: 0x%x\n", __func__, cpr_info->turbo_quot);
+ pr_debug("%s: cpr: pvs_fuse: 0x%x\n", __func__, cpr_info->pvs_fuse);
+ kfree(cpr_info);
+
+ /* Select TCXO (19.2MHz) as clock source */
+ reg_val = readl_relaxed(A11S_TEST_BUS_SEL_ADDR);
+ reg_val |= RBCPR_CLK_MUX_SEL;
+ writel_relaxed(reg_val, A11S_TEST_BUS_SEL_ADDR);
+
+ /* Get CPR out of reset */
+ writel_relaxed(0x1, RBCPR_SW_RESET_N);
+
+ platform_device_register(&msm8625_vp_device);
+ platform_device_register(&msm8625_device_cpr);
+}
+
static struct clk_lookup msm_clock_8625_dummy[] = {
CLK_DUMMY("core_clk", adm_clk.c, "msm_dmov", 0),
CLK_DUMMY("adsp_clk", adsp_clk.c, NULL, 0),
@@ -1645,7 +1823,6 @@
.table = msm_clock_8625_dummy,
.size = ARRAY_SIZE(msm_clock_8625_dummy),
};
-
enum {
MSM8625,
MSM8625A,
@@ -1691,6 +1868,7 @@
{
if (machine_is_msm8625_rumi3()) {
msm_clock_init(&msm8625_dummy_clock_init_data);
+ msm_cpr_init();
return 0;
}
@@ -1707,6 +1885,11 @@
} else {
platform_device_register(&msm7x27a_device_acpuclk);
}
+
+ if (cpu_is_msm8625() &&
+ (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2))
+ msm_cpr_init();
+
return 0;
}