msm: acpuclock: Implement acpuclock APIs through function pointers
Create a generic wrapper acpuclock driver in acpuclock.c to call
SoC-specific function pointer API implementations. With the
exception of iomap conflicts, this should allow multiple acpuclock
driver implementations to be compiled into the same kernel binary.
Signed-off-by: Matt Wagantall <mattw@codeaurora.org>
Conflicts:
arch/arm/mach-msm/acpuclock-7201.c
arch/arm/mach-msm/board-msm8960.c
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index a23b564..6c40fdc 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -17,6 +17,7 @@
endif
endif
+obj-y += acpuclock.o
obj-$(CONFIG_ARCH_MSM_ARM11) += acpuclock-7201.o
obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
obj-$(CONFIG_ARCH_MSM_CORTEX_A5) += acpuclock-7201.o
diff --git a/arch/arm/mach-msm/acpuclock-7201.c b/arch/arm/mach-msm/acpuclock-7201.c
index 9422cda..f06b069 100644
--- a/arch/arm/mach-msm/acpuclock-7201.c
+++ b/arch/arm/mach-msm/acpuclock-7201.c
@@ -46,6 +46,8 @@
#define PLL4_MODE (MSM_CLK_CTL_BASE + 0x374)
#define PLL4_L_VAL (MSM_CLK_CTL_BASE + 0x378)
+#define POWER_COLLAPSE_KHZ 19200
+
/* Max CPU frequency allowed by hardware while in standby waiting for an irq. */
#define MAX_WAIT_FOR_IRQ_KHZ 128000
@@ -77,7 +79,6 @@
uint32_t max_speed_delta_khz;
uint32_t vdd_switch_time_us;
unsigned long max_axi_khz;
- unsigned long wait_for_irq_khz;
struct clk *ebi1_clk;
};
@@ -120,8 +121,6 @@
static struct clock_state drv_state = { 0 };
static struct clkctl_acpu_speed *acpu_freq_tbl;
-static void __init acpuclk_init(void);
-
/*
* ACPU freq tables used for different PLLs frequency combinations. The
* correct table is selected during init.
@@ -484,23 +483,6 @@
* ARM11 'owned' clock control
*---------------------------------------------------------------------------*/
-#define POWER_COLLAPSE_KHZ 19200
-unsigned long acpuclk_power_collapse(void)
-{
- int ret = acpuclk_get_rate(smp_processor_id());
- acpuclk_set_rate(smp_processor_id(), POWER_COLLAPSE_KHZ, SETRATE_PC);
- return ret;
-}
-
-unsigned long acpuclk_wait_for_irq(void)
-{
- int rate = acpuclk_get_rate(smp_processor_id());
- if (rate > MAX_WAIT_FOR_IRQ_KHZ)
- acpuclk_set_rate(smp_processor_id(), drv_state.wait_for_irq_khz,
- SETRATE_SWFI);
- return rate;
-}
-
static int acpuclk_set_vdd_level(int vdd)
{
uint32_t current_vdd;
@@ -575,7 +557,8 @@
}
}
-int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
+static int acpuclk_7201_set_rate(int cpu, unsigned long rate,
+ enum setrate_reason reason)
{
uint32_t reg_clkctl;
struct clkctl_acpu_speed *cur_s, *tgt_s, *strt_s;
@@ -587,7 +570,7 @@
strt_s = cur_s = drv_state.current_speed;
- WARN_ONCE(cur_s == NULL, "acpuclk_set_rate: not initialized\n");
+ WARN_ONCE(cur_s == NULL, "%s: not initialized\n", __func__);
if (cur_s == NULL) {
rc = -ENOENT;
goto out;
@@ -751,7 +734,7 @@
return rc;
}
-static void __init acpuclk_init(void)
+static void __init acpuclk_hw_init(void)
{
struct clkctl_acpu_speed *speed;
uint32_t div, sel, reg_clksel;
@@ -811,21 +794,16 @@
pr_info("ACPU running at %d KHz\n", speed->a11clk_khz);
}
-unsigned long acpuclk_get_rate(int cpu)
+static unsigned long acpuclk_7201_get_rate(int cpu)
{
WARN_ONCE(drv_state.current_speed == NULL,
- "acpuclk_get_rate: not initialized\n");
+ "%s: not initialized\n", __func__);
if (drv_state.current_speed)
return drv_state.current_speed->a11clk_khz;
else
return 0;
}
-uint32_t acpuclk_get_switch_time(void)
-{
- return drv_state.acpu_switch_time_us;
-}
-
/*----------------------------------------------------------------------------
* Clock driver initialization
*---------------------------------------------------------------------------*/
@@ -1080,29 +1058,39 @@
pr_warning("Falling back to proc_comm PLL control.\n");
}
-void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
+static struct acpuclk_data acpuclk_7201_data = {
+ .set_rate = acpuclk_7201_set_rate,
+ .get_rate = acpuclk_7201_get_rate,
+ .power_collapse_khz = POWER_COLLAPSE_KHZ,
+};
+
+int __init acpuclk_7201_init(struct acpuclk_platform_data *clkdata)
{
- pr_info("acpu_clock_init()\n");
+ pr_info("%s()\n", __func__);
drv_state.ebi1_clk = clk_get(NULL, "ebi1_acpu_clk");
BUG_ON(IS_ERR(drv_state.ebi1_clk));
mutex_init(&drv_state.lock);
shared_pll_control_init();
+ acpuclk_7201_data.switch_time_us = clkdata->acpu_switch_time_us;
drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us;
drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz;
drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us;
drv_state.max_axi_khz = clkdata->max_axi_khz;
acpu_freq_tbl_fixup();
- drv_state.wait_for_irq_khz = find_wait_for_irq_khz();
+ acpuclk_7201_data.wait_for_irq_khz = find_wait_for_irq_khz();
precompute_stepping();
if (cpu_is_msm7x25())
msm7x25_acpu_pll_hw_bug_fix();
- acpuclk_init();
+ acpuclk_hw_init();
lpj_init();
print_acpu_freq_tbl();
+ acpuclk_register(&acpuclk_7201_data);
+
#ifdef CONFIG_CPU_FREQ_MSM
cpufreq_table_init();
cpufreq_frequency_table_get_attr(freq_table, smp_processor_id());
#endif
+ return 0;
}
diff --git a/arch/arm/mach-msm/acpuclock-7x30.c b/arch/arm/mach-msm/acpuclock-7x30.c
index 2180a8d..0da4322 100644
--- a/arch/arm/mach-msm/acpuclock-7x30.c
+++ b/arch/arm/mach-msm/acpuclock-7x30.c
@@ -56,7 +56,6 @@
struct clock_state {
struct clkctl_acpu_speed *current_speed;
struct mutex lock;
- uint32_t acpu_switch_time_us;
uint32_t vdd_switch_time_us;
struct clk *ebi1_clk;
};
@@ -133,22 +132,6 @@
{ 0 }
};
-#define POWER_COLLAPSE_KHZ MAX_AXI_KHZ
-unsigned long acpuclk_power_collapse(void)
-{
- int ret = acpuclk_get_rate(smp_processor_id());
- acpuclk_set_rate(smp_processor_id(), POWER_COLLAPSE_KHZ, SETRATE_PC);
- return ret;
-}
-
-#define WAIT_FOR_IRQ_KHZ MAX_AXI_KHZ
-unsigned long acpuclk_wait_for_irq(void)
-{
- int ret = acpuclk_get_rate(smp_processor_id());
- acpuclk_set_rate(smp_processor_id(), WAIT_FOR_IRQ_KHZ, SETRATE_SWFI);
- return ret;
-}
-
static int acpuclk_set_acpu_vdd(struct clkctl_acpu_speed *s)
{
int ret = msm_spm_set_vdd(0, s->vdd_raw);
@@ -207,7 +190,8 @@
mb();
}
-int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
+static int acpuclk_7x30_set_rate(int cpu, unsigned long rate,
+ enum setrate_reason reason)
{
struct clkctl_acpu_speed *tgt_s, *strt_s;
int res, rc = 0;
@@ -320,7 +304,7 @@
return rc;
}
-unsigned long acpuclk_get_rate(int cpu)
+static unsigned long acpuclk_7x30_get_rate(int cpu)
{
WARN_ONCE(drv_state.current_speed == NULL,
"acpuclk_get_rate: not initialized\n");
@@ -330,16 +314,11 @@
return 0;
}
-uint32_t acpuclk_get_switch_time(void)
-{
- return drv_state.acpu_switch_time_us;
-}
-
/*----------------------------------------------------------------------------
* Clock driver initialization
*---------------------------------------------------------------------------*/
-static void __init acpuclk_init(void)
+static void __init acpuclk_hw_init(void)
{
struct clkctl_acpu_speed *s;
uint32_t div, sel, src_num;
@@ -487,16 +466,26 @@
BUG_ON(IS_ERR(acpuclk_sources[PLL_3]));
}
-void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
+static struct acpuclk_data acpuclk_7x30_data = {
+ .set_rate = acpuclk_7x30_set_rate,
+ .get_rate = acpuclk_7x30_get_rate,
+ .power_collapse_khz = MAX_AXI_KHZ,
+ .wait_for_irq_khz = MAX_AXI_KHZ,
+};
+
+int __init acpuclk_7x30_init(struct acpuclk_platform_data *clkdata)
{
- pr_info("acpu_clock_init()\n");
+ pr_info("%s()\n", __func__);
mutex_init(&drv_state.lock);
- drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us;
+ acpuclk_7x30_data.switch_time_us = clkdata->acpu_switch_time_us;
drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us;
pll2_fixup();
populate_plls();
- acpuclk_init();
+ acpuclk_hw_init();
lpj_init();
setup_cpufreq_table();
+ acpuclk_register(&acpuclk_7x30_data);
+
+ return 0;
}
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index edac8bb..19dbb8a 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -359,30 +359,11 @@
{ 0, { 0 } }
};
-unsigned long acpuclk_get_rate(int cpu)
+static unsigned long acpuclk_8960_get_rate(int cpu)
{
return scalable[cpu].current_speed->khz;
}
-uint32_t acpuclk_get_switch_time(void)
-{
- return 0;
-}
-
-unsigned long acpuclk_power_collapse(void)
-{
- int ret = acpuclk_get_rate(smp_processor_id());
- acpuclk_set_rate(smp_processor_id(), STBY_KHZ, SETRATE_PC);
- return ret;
-}
-
-unsigned long acpuclk_wait_for_irq(void)
-{
- int ret = acpuclk_get_rate(smp_processor_id());
- acpuclk_set_rate(smp_processor_id(), STBY_KHZ, SETRATE_SWFI);
- return ret;
-}
-
/* Read an 'indirectly' addressed L2 CP15 register. */
static uint32_t readl_cp15_l2ind(uint32_t addr)
{
@@ -758,7 +739,8 @@
}
/* Set the CPU's clock rate and adjust the L2 rate, if appropriate. */
-int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
+static int acpuclk_8960_set_rate(int cpu, unsigned long rate,
+ enum setrate_reason reason)
{
struct core_speed *strt_acpu_s, *tgt_acpu_s;
struct l2_level *tgt_l2_l;
@@ -814,7 +796,7 @@
/*
* Update the L2 vote and apply the rate change. A spinlock is
* necessary to ensure L2 rate is calulated and set atomically,
- * even if acpuclk_set_rate() is called from an atomic context
+ * even if acpuclk_8960_set_rate() is called from an atomic context
* and the driver_lock mutex is not acquired.
*/
spin_lock_irqsave(&l2_lock, flags);
@@ -925,8 +907,8 @@
sc->current_speed = tgt_s;
/*
- * Set this flag so that the first call to acpuclk_set_rate() can drop
- * voltages and set initial bus bandwidth requests.
+ * Set this flag so that the first call to acpuclk_8960_set_rate() can
+ * drop voltages and set initial bus bandwidth requests.
*/
sc->first_set_call = true;
}
@@ -1016,17 +998,17 @@
break;
case CPU_DEAD:
case CPU_DEAD_FROZEN:
- prev_khz[cpu] = acpuclk_get_rate(cpu);
+ prev_khz[cpu] = acpuclk_8960_get_rate(cpu);
/* Fall through. */
case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN:
- acpuclk_set_rate(cpu, HOT_UNPLUG_KHZ, SETRATE_HOTPLUG);
+ acpuclk_8960_set_rate(cpu, HOT_UNPLUG_KHZ, SETRATE_HOTPLUG);
break;
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
if (WARN_ON(!prev_khz[cpu]))
prev_khz[cpu] = acpu_freq_tbl->speed.khz;
- acpuclk_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
+ acpuclk_8960_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
break;
case CPU_STARTING:
case CPU_STARTING_FROZEN:
@@ -1046,7 +1028,14 @@
.notifier_call = acpuclock_cpu_callback,
};
-void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
+static struct acpuclk_data acpuclk_8960_data = {
+ .set_rate = acpuclk_8960_set_rate,
+ .get_rate = acpuclk_8960_get_rate,
+ .power_collapse_khz = STBY_KHZ,
+ .wait_for_irq_khz = STBY_KHZ,
+};
+
+int __init acpuclk_8960_init(struct acpuclk_platform_data *data)
{
if (cpu_is_msm8960()) {
scalable = scalable_8960;
@@ -1070,5 +1059,9 @@
regulator_init();
bus_init();
cpufreq_table_init();
+
+ acpuclk_register(&acpuclk_8960_data);
register_hotcpu_notifier(&acpuclock_cpu_notifier);
+
+ return 0;
}
diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c
index 1b2416a..be0cf5b 100644
--- a/arch/arm/mach-msm/acpuclock-8x50.c
+++ b/arch/arm/mach-msm/acpuclock-8x50.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -114,11 +114,11 @@
/* Use 128MHz for PC since ACPU will auto-switch to AXI (128MHz) before
* coming back up. This allows detection of return-from-PC, since 128MHz
* is only used for power collapse. */
-#define POWER_COLLAPSE_KHZ (AXI_S->acpuclk_khz)
+#define POWER_COLLAPSE_KHZ 128000
/* Use 245MHz (not 128MHz) for SWFI to avoid unnecessary steps between
* 128MHz<->245MHz. Jumping to high frequencies from 128MHz directly
* is not allowed. */
-#define WAIT_FOR_IRQ_KHZ (PLL0_S->acpuclk_khz)
+#define WAIT_FOR_IRQ_KHZ 245760
#ifdef CONFIG_CPU_FREQ_MSM
static struct cpufreq_frequency_table freq_table[20];
@@ -155,8 +155,6 @@
struct clock_state {
struct clkctl_acpu_speed *current_speed;
struct mutex lock;
- uint32_t acpu_switch_time_us;
- uint32_t max_speed_delta_khz;
uint32_t vdd_switch_time_us;
unsigned int max_vdd;
struct clk *ebi1_clk;
@@ -391,7 +389,8 @@
}
}
-int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
+static int acpuclk_8x50_set_rate(int cpu, unsigned long rate,
+ enum setrate_reason reason)
{
struct clkctl_acpu_speed *tgt_s, *strt_s;
int res, rc = 0;
@@ -500,7 +499,7 @@
return rc;
}
-static void __init acpuclk_init(void)
+static void __init acpuclk_hw_init(void)
{
struct clkctl_acpu_speed *speed;
uint32_t div, sel, regval;
@@ -567,30 +566,11 @@
pr_info("ACPU running at %d KHz\n", speed->acpuclk_khz);
}
-unsigned long acpuclk_get_rate(int cpu)
+static unsigned long acpuclk_8x50_get_rate(int cpu)
{
return drv_state.current_speed->acpuclk_khz;
}
-uint32_t acpuclk_get_switch_time(void)
-{
- return drv_state.acpu_switch_time_us;
-}
-
-unsigned long acpuclk_power_collapse(void)
-{
- int ret = acpuclk_get_rate(smp_processor_id());
- acpuclk_set_rate(smp_processor_id(), POWER_COLLAPSE_KHZ, SETRATE_PC);
- return ret;
-}
-
-unsigned long acpuclk_wait_for_irq(void)
-{
- int ret = acpuclk_get_rate(smp_processor_id());
- acpuclk_set_rate(smp_processor_id(), WAIT_FOR_IRQ_KHZ, SETRATE_SWFI);
- return ret;
-}
-
/* Spare register populated with efuse data on max ACPU freq. */
#define CT_CSR_PHYS 0xA8700000
#define TCSR_SPARE2_ADDR (ct_csr_base + 0x60)
@@ -689,11 +669,17 @@
}
#endif
-void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
+static struct acpuclk_data acpuclk_8x50_data = {
+ .set_rate = acpuclk_8x50_set_rate,
+ .get_rate = acpuclk_8x50_get_rate,
+ .power_collapse_khz = POWER_COLLAPSE_KHZ,
+ .wait_for_irq_khz = WAIT_FOR_IRQ_KHZ,
+};
+
+int __init acpuclk_8x50_init(struct acpuclk_platform_data *clkdata)
{
mutex_init(&drv_state.lock);
- drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us;
- drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz;
+ acpuclk_8x50_data.switch_time_us = clkdata->acpu_switch_time_us;
drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us;
drv_state.max_vdd = clkdata->max_vdd;
drv_state.acpu_set_vdd = clkdata->acpu_set_vdd;
@@ -702,13 +688,15 @@
BUG_ON(IS_ERR(drv_state.ebi1_clk));
acpu_freq_tbl_fixup();
- acpuclk_init();
+ acpuclk_hw_init();
lpj_init();
/* Set a lower bound for ACPU rate for boot. This limits the
* maximum frequency hop caused by the first CPUFREQ switch. */
if (drv_state.current_speed->acpuclk_khz < PLL0_S->acpuclk_khz)
acpuclk_set_rate(0, PLL0_S->acpuclk_khz, SETRATE_CPUFREQ);
+ acpuclk_register(&acpuclk_8x50_data);
+
#ifdef CONFIG_CPU_FREQ_MSM
cpufreq_table_init();
cpufreq_frequency_table_get_attr(freq_table, smp_processor_id());
@@ -720,4 +708,5 @@
drv_state.acpu_set_vdd = NULL;
}
#endif
+ return 0;
}
diff --git a/arch/arm/mach-msm/acpuclock-8x60.c b/arch/arm/mach-msm/acpuclock-8x60.c
index d840865..b7d0589 100644
--- a/arch/arm/mach-msm/acpuclock-8x60.c
+++ b/arch/arm/mach-msm/acpuclock-8x60.c
@@ -115,9 +115,6 @@
struct clkctl_l2_speed *current_l2_speed;
spinlock_t l2_lock;
struct mutex lock;
- uint32_t acpu_switch_time_us;
- uint32_t vdd_switch_time_us;
- uint32_t max_speed_delta_khz;
} drv_state;
struct clkctl_l2_speed {
@@ -318,32 +315,11 @@
static struct clkctl_l2_speed *l2_freq_tbl = l2_freq_tbl_v2;
static unsigned int l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_v2);
-unsigned long acpuclk_get_rate(int cpu)
+static unsigned long acpuclk_8x60_get_rate(int cpu)
{
return drv_state.current_speed[cpu]->acpuclk_khz;
}
-uint32_t acpuclk_get_switch_time(void)
-{
- return drv_state.acpu_switch_time_us;
-}
-
-#define POWER_COLLAPSE_KHZ MAX_AXI
-unsigned long acpuclk_power_collapse(void)
-{
- int ret = acpuclk_get_rate(smp_processor_id());
- acpuclk_set_rate(smp_processor_id(), POWER_COLLAPSE_KHZ, SETRATE_PC);
- return ret;
-}
-
-#define WAIT_FOR_IRQ_KHZ MAX_AXI
-unsigned long acpuclk_wait_for_irq(void)
-{
- int ret = acpuclk_get_rate(smp_processor_id());
- acpuclk_set_rate(smp_processor_id(), WAIT_FOR_IRQ_KHZ, SETRATE_SWFI);
- return ret;
-}
-
static void select_core_source(unsigned int id, unsigned int src)
{
uint32_t regval;
@@ -595,7 +571,8 @@
drv_state.current_speed[cpu] = tgt_s;
}
-int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
+static int acpuclk_8x60_set_rate(int cpu, unsigned long rate,
+ enum setrate_reason reason)
{
struct clkctl_acpu_speed *tgt_s, *strt_s;
struct clkctl_l2_speed *tgt_l2;
@@ -859,17 +836,17 @@
switch (action) {
case CPU_DEAD:
case CPU_DEAD_FROZEN:
- prev_khz[cpu] = acpuclk_get_rate(cpu);
+ prev_khz[cpu] = acpuclk_8x60_get_rate(cpu);
/* Fall through. */
case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN:
- acpuclk_set_rate(cpu, HOT_UNPLUG_KHZ, SETRATE_HOTPLUG);
+ acpuclk_8x60_set_rate(cpu, HOT_UNPLUG_KHZ, SETRATE_HOTPLUG);
break;
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
if (WARN_ON(!prev_khz[cpu]))
prev_khz[cpu] = acpu_freq_tbl->acpuclk_khz;
- acpuclk_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
+ acpuclk_8x60_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
break;
default:
break;
@@ -936,15 +913,20 @@
return f->acpuclk_khz;
}
-void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
+static struct acpuclk_data acpuclk_8x60_data = {
+ .set_rate = acpuclk_8x60_set_rate,
+ .get_rate = acpuclk_8x60_get_rate,
+ .power_collapse_khz = MAX_AXI,
+ .wait_for_irq_khz = MAX_AXI,
+};
+
+int __init acpuclk_8x60_init(struct acpuclk_platform_data *clkdata)
{
unsigned int max_cpu_khz;
int cpu;
mutex_init(&drv_state.lock);
spin_lock_init(&drv_state.l2_lock);
- drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us;
- drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us;
/* Configure hardware. */
max_cpu_khz = select_freq_plan();
@@ -958,8 +940,11 @@
/* Improve boot time by ramping up CPUs immediately. */
for_each_online_cpu(cpu)
- acpuclk_set_rate(cpu, max_cpu_khz, SETRATE_INIT);
+ acpuclk_8x60_set_rate(cpu, max_cpu_khz, SETRATE_INIT);
+ acpuclk_register(&acpuclk_8x60_data);
cpufreq_table_init();
register_hotcpu_notifier(&acpuclock_cpu_notifier);
+
+ return 0;
}
diff --git a/arch/arm/mach-msm/acpuclock-fsm9xxx.c b/arch/arm/mach-msm/acpuclock-fsm9xxx.c
index b12eb9e..4acae13 100644
--- a/arch/arm/mach-msm/acpuclock-fsm9xxx.c
+++ b/arch/arm/mach-msm/acpuclock-fsm9xxx.c
@@ -20,7 +20,7 @@
/* Registers */
#define PLL1_CTL_ADDR (MSM_CLK_CTL_BASE + 0x604)
-unsigned long acpuclk_get_rate(int cpu)
+static unsigned long acpuclk_9xxx_get_rate(int cpu)
{
unsigned int pll1_ctl;
unsigned int pll1_l, pll1_div2;
@@ -36,7 +36,13 @@
return pll1_khz;
}
-void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
+static struct acpuclk_data acpuclk_9xxx_data = {
+ .get_rate = acpuclk_9xxx_get_rate,
+};
+
+int __init acpuclk_9xxx_init(struct acpuclk_platform_data *clkdata)
{
+ acpuclk_register(&acpuclk_9xxx_data);
pr_info("ACPU running at %lu KHz\n", acpuclk_get_rate(0));
+ return 0;
}
diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c
new file mode 100644
index 0000000..4aced18
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock.c
@@ -0,0 +1,75 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/cpu.h>
+#include "acpuclock.h"
+
+static struct acpuclk_data *acpuclk_data;
+
+unsigned long acpuclk_get_rate(int cpu)
+{
+ if (!acpuclk_data->get_rate)
+ return 0;
+
+ return acpuclk_data->get_rate(cpu);
+}
+
+int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
+{
+ if (!acpuclk_data->set_rate)
+ return 0;
+
+ return acpuclk_data->set_rate(cpu, rate, reason);
+}
+
+uint32_t acpuclk_get_switch_time(void)
+{
+ return acpuclk_data->switch_time_us;
+}
+
+unsigned long acpuclk_power_collapse(void)
+{
+ unsigned long rate = acpuclk_get_rate(smp_processor_id());
+ acpuclk_set_rate(smp_processor_id(), acpuclk_data->power_collapse_khz,
+ SETRATE_PC);
+ return rate;
+}
+
+unsigned long acpuclk_wait_for_irq(void)
+{
+ unsigned long rate = acpuclk_get_rate(smp_processor_id());
+ acpuclk_set_rate(smp_processor_id(), acpuclk_data->wait_for_irq_khz,
+ SETRATE_SWFI);
+ return rate;
+}
+
+void __init acpuclk_register(struct acpuclk_data *data)
+{
+ acpuclk_data = data;
+}
+
+int __init acpuclk_init(struct acpuclk_platform_data *pdata)
+{
+ int rc;
+
+ if (!pdata->init)
+ return -EINVAL;
+
+ rc = pdata->init(pdata);
+ if (rc)
+ return rc;
+
+ if (!acpuclk_data)
+ return -ENODEV;
+
+ return 0;
+}
diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h
index 6fa2e3b..4a8bf29 100644
--- a/arch/arm/mach-msm/acpuclock.h
+++ b/arch/arm/mach-msm/acpuclock.h
@@ -1,9 +1,8 @@
-/* arch/arm/mach-msm/acpuclock.h
- *
- * MSM architecture clock driver header
+/*
+ * MSM architecture CPU clock driver header
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
* Author: San Mehat <san@android.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -20,8 +19,9 @@
#ifndef __ARCH_ARM_MACH_MSM_ACPUCLOCK_H
#define __ARCH_ARM_MACH_MSM_ACPUCLOCK_H
-#include <linux/list.h>
-
+/**
+ * enum setrate_reason - Reasons for use with acpuclk_set_rate()
+ */
enum setrate_reason {
SETRATE_CPUFREQ = 0,
SETRATE_SWFI,
@@ -30,10 +30,84 @@
SETRATE_INIT,
};
-int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason);
+/**
+ * struct acpuclk_platform_data - Platform data for acpuclk_init()
+ */
+struct acpuclk_platform_data {
+ uint32_t acpu_switch_time_us;
+ unsigned long max_speed_delta_khz;
+ uint32_t vdd_switch_time_us;
+ unsigned int max_axi_khz;
+ unsigned int max_vdd;
+ int (*acpu_set_vdd) (int mvolts);
+ int (*init)(struct acpuclk_platform_data *);
+};
+
+/**
+ * struct acpuclk_data - Function pointers and data for function implementations
+ */
+struct acpuclk_data {
+ unsigned long (*get_rate)(int cpu);
+ int (*set_rate)(int cpu, unsigned long rate, enum setrate_reason);
+ uint32_t switch_time_us;
+ unsigned long power_collapse_khz;
+ unsigned long wait_for_irq_khz;
+};
+
+/**
+ * acpulock_get_rate() - Get a CPU's clock rate in KHz
+ * @cpu: CPU to query the rate of
+ */
unsigned long acpuclk_get_rate(int cpu);
+
+/**
+ * acpuclk_set_rate() - Set a CPU's clock rate
+ * @cpu: CPU to set rate of
+ * @rate: Desired rate in KHz
+ * @setrate_reason: Reason for the rate switch
+ *
+ * Returns 0 for success.
+ */
+int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason);
+
+/**
+ * acpuclk_get_switch_time() - Query estimated time in us for a CPU rate switch
+ */
uint32_t acpuclk_get_switch_time(void);
-unsigned long acpuclk_wait_for_irq(void);
+
+/**
+ * acpuclk_power_collapse() - Prepare current CPU clocks for power-collapse
+ *
+ * Returns the previous rate of the CPU in KHz.
+ */
unsigned long acpuclk_power_collapse(void);
+/**
+ * acpuclk_wait_for_irq() - Prepare current CPU clocks for SWFI
+ *
+ * Returns the previous rate of the CPU in KHz.
+ */
+unsigned long acpuclk_wait_for_irq(void);
+
+/**
+ * acpuclk_register() - Register acpuclk_data function implementations
+ * @data: acpuclock API implementations and data
+ */
+void acpuclk_register(struct acpuclk_data *data);
+
+/**
+ * acpuclk_init() - acpuclock driver initialization function
+ *
+ * Return 0 for success.
+ */
+int acpuclk_init(struct acpuclk_platform_data *);
+
+/* SoC-specific acpuclock initialization functions. */
+int acpuclk_7201_init(struct acpuclk_platform_data *);
+int acpuclk_7x30_init(struct acpuclk_platform_data *);
+int acpuclk_8x50_init(struct acpuclk_platform_data *);
+int acpuclk_8x60_init(struct acpuclk_platform_data *);
+int acpuclk_8960_init(struct acpuclk_platform_data *);
+int acpuclk_9xxx_init(struct acpuclk_platform_data *);
+
#endif
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 0053734..9c1e72ff 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -39,6 +39,7 @@
#include <mach/socinfo.h>
#include "devices.h"
#include "timer.h"
+#include "acpuclock.h"
#include "pm.h"
#include "spm.h"
#include <linux/regulator/consumer.h>
@@ -834,9 +835,10 @@
&fsm_xo_device,
};
-static struct msm_acpu_clock_platform_data fsm9xxx_clock_data = {
+static struct acpuclk_platform_data fsm9xxx_clock_data __initdata = {
.acpu_switch_time_us = 50,
.vdd_switch_time_us = 62,
+ .init = acpuclk_9xxx_init,
};
static void __init fsm9xxx_init_irq(void)
@@ -877,7 +879,7 @@
pr_err("%s: socinfo_init() failed!\n",
__func__);
- msm_acpu_clock_init(&fsm9xxx_clock_data);
+ acpuclk_init(&fsm9xxx_clock_data);
regulator_has_full_constraints();
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index 3959bf2..bf1c4b4 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -60,6 +60,7 @@
#include "devices.h"
#include "clock.h"
+#include "acpuclock.h"
#include "msm-keypad-devices.h"
#include "pm.h"
@@ -1488,11 +1489,12 @@
msm_init_irq();
}
-static struct msm_acpu_clock_platform_data msm7x2x_clock_data = {
+static struct acpuclk_platform_data msm7x2x_clock_data __initdata = {
.acpu_switch_time_us = 50,
.max_speed_delta_khz = 400000,
.vdd_switch_time_us = 62,
.max_axi_khz = 160000,
+ .init = acpuclk_7201_init,
};
void msm_serial_debug_init(unsigned int base, int irq,
@@ -1894,7 +1896,7 @@
if (cpu_is_msm7x27())
msm7x2x_clock_data.max_axi_khz = 200000;
- msm_acpu_clock_init(&msm7x2x_clock_data);
+ acpuclk_init(&msm7x2x_clock_data);
usb_mpp_init();
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 10dcc68..edebbd8 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -80,6 +80,7 @@
#endif
#include "pm.h"
#include "spm.h"
+#include "acpuclock.h"
#include <mach/dal_axi.h>
#include <mach/msm_serial_hs.h>
#include <mach/qdsp5v2/mi2s.h>
@@ -5523,9 +5524,10 @@
};
#endif
-static struct msm_acpu_clock_platform_data msm7x30_clock_data = {
+static struct acpuclk_platform_data msm7x30_clock_data __initdata = {
.acpu_switch_time_us = 50,
.vdd_switch_time_us = 62,
+ .init = acpuclk_7x30_init,
};
static void __init msm7x30_init_irq(void)
@@ -6953,7 +6955,7 @@
msm7x30_init_uart2();
#endif
msm_spm_init(&msm_spm_data, 1);
- msm_acpu_clock_init(&msm7x30_clock_data);
+ acpuclk_init(&msm7x30_clock_data);
if (machine_is_msm7x30_surf() || machine_is_msm7x30_fluid())
msm7x30_cfg_smsc911x();
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 4882772..a135037 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -79,6 +79,7 @@
#include "cpuidle.h"
#include "rpm_resources.h"
#include "mpm.h"
+#include "acpuclock.h"
static struct platform_device msm_fm_platform_init = {
.name = "iris_fm",
@@ -1930,9 +1931,10 @@
return 0;
}
-static struct msm_acpu_clock_platform_data msm8960_acpu_clock_data = {
+static struct acpuclk_platform_data msm8960_acpuclk_data __initdata = {
.acpu_switch_time_us = 0,
.vdd_switch_time_us = 0,
+ .init = acpuclk_8960_init,
};
#define MSM_SHARED_RAM_PHYS 0x80000000
@@ -3510,7 +3512,7 @@
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
pm8921_gpio_mpp_init();
platform_add_devices(sim_devices, ARRAY_SIZE(sim_devices));
- msm_acpu_clock_init(&msm8960_acpu_clock_data);
+ acpuclk_init(&msm8960_acpuclk_data);
msm8960_device_qup_spi_gsbi1.dev.platform_data =
&msm8960_qup_spi_gsbi1_pdata;
@@ -3601,7 +3603,7 @@
platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
msm8960_init_cam();
msm8960_init_mmc();
- msm_acpu_clock_init(&msm8960_acpu_clock_data);
+ acpuclk_init(&msm8960_acpuclk_data);
register_i2c_devices();
msm8960_wcnss_init();
msm_fb_add_devices();
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 0f82943..792f42b 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -102,6 +102,7 @@
#include "peripheral-loader.h"
#include <linux/platform_data/qcom_crypto_device.h>
#include "rpm_resources.h"
+#include "acpuclock.h"
#define MSM_SHARED_RAM_PHYS 0x40000000
@@ -397,7 +398,8 @@
},
};
-static struct msm_acpu_clock_platform_data msm8x60_acpu_clock_data = {
+static struct acpuclk_platform_data msm8x60_acpuclk_data __initdata = {
+ .init = acpuclk_8x60_init,
};
/*
@@ -10058,7 +10060,7 @@
platform_add_devices(early_devices, ARRAY_SIZE(early_devices));
/* CPU frequency control is not supported on simulated targets. */
if (!machine_is_msm8x60_rumi3() && !machine_is_msm8x60_sim())
- msm_acpu_clock_init(&msm8x60_acpu_clock_data);
+ acpuclk_init(&msm8x60_acpuclk_data);
/* No EBI2 on 8660 charm targets */
if (!machine_is_msm8x60_fusion() && !machine_is_msm8x60_fusn_ffa())
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index e8f394a..c99dc6d 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -54,6 +54,7 @@
#include "devices.h"
#include "timer.h"
#include "msm-keypad-devices.h"
+#include "acpuclock.h"
#include "pm.h"
#include "proc_comm.h"
#ifdef CONFIG_USB_ANDROID
@@ -1239,12 +1240,13 @@
return rc;
}
-static struct msm_acpu_clock_platform_data qsd8x50_clock_data = {
+static struct acpuclk_platform_data qsd8x50_clock_data __initdata = {
.acpu_switch_time_us = 20,
.max_speed_delta_khz = 256000,
.vdd_switch_time_us = 62,
.max_vdd = TPS65023_MAX_DCDC1,
.acpu_set_vdd = qsd8x50_tps65023_set_dcdc1,
+ .init = acpuclk_8x50_init,
};
@@ -2442,7 +2444,7 @@
__func__);
msm_clock_init(&qds8x50_clock_init_data);
qsd8x50_cfg_smc91x();
- msm_acpu_clock_init(&qsd8x50_clock_data);
+ acpuclk_init(&qsd8x50_clock_data);
msm_hsusb_pdata.swfi_latency =
msm_pm_data
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 725f47f..fe40248 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -29,6 +29,7 @@
#include "devices.h"
#include "devices-msm7x2xa.h"
#include "footswitch.h"
+#include "acpuclock.h"
/* Address of GSBI blocks */
#define MSM_GSBI0_PHYS 0xA1200000
@@ -694,11 +695,12 @@
.id = 0,
};
-static struct msm_acpu_clock_platform_data msm7x2x_clock_data = {
+static struct acpuclk_platform_data msm7x2x_clock_data __initdata = {
.acpu_switch_time_us = 50,
.max_speed_delta_khz = 400000,
.vdd_switch_time_us = 62,
.max_axi_khz = 200000,
+ .init = acpuclk_7201_init,
};
int __init msm7x2x_misc_init(void)
@@ -710,7 +712,7 @@
msm7x2x_clock_data.max_speed_delta_khz = 504000;
msm_clock_init(&msm7x27a_clock_init_data);
- msm_acpu_clock_init(&msm7x2x_clock_data);
+ acpuclk_init(&msm7x2x_clock_data);
return 0;
}
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index bd0679f..a537b4f 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -28,16 +28,6 @@
#include <mach/msm_bus.h>
#endif
-/* platform device data structures */
-struct msm_acpu_clock_platform_data {
- uint32_t acpu_switch_time_us;
- uint32_t max_speed_delta_khz;
- uint32_t vdd_switch_time_us;
- unsigned int max_axi_khz;
- unsigned int max_vdd;
- int (*acpu_set_vdd) (int mvolts);
-};
-
struct msm_camera_io_ext {
uint32_t mdcphy;
uint32_t mdcsz;
@@ -383,7 +373,6 @@
void __init msm_map_msm7x30_io(void);
void __init msm_map_fsm9xxx_io(void);
void __init msm_init_irq(void);
-void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *);
struct mmc_platform_data;
int __init msm_add_sdcc(unsigned int controller,