msm: acpuclock-krait: Support booting with fewer CPUs
Allow booting with only a subset of the CPUs enabled by default. The
others can potentially be added later with hotplug, at which point
the voltage, bus and clock requests for them will be applied.
Change-Id: Iff0758e6d3c79435c2c144da70079c8d60626224
Signed-off-by: Matt Wagantall <mattw@codeaurora.org>
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index 4dc47d2..e7e328f 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -54,6 +54,7 @@
static struct drv_data {
struct acpu_level *acpu_freq_tbl;
+ const struct acpu_level *max_acpu_lvl;
const struct l2_level *l2_freq_tbl;
struct scalable *scalable;
u32 bus_perf_client;
@@ -483,8 +484,8 @@
hfpll_enable(sc, false);
}
-static void __init rpm_regulator_init(struct scalable *sc, enum vregs vreg,
- int vdd, bool enable)
+static void __cpuinit rpm_regulator_init(struct scalable *sc, enum vregs vreg,
+ int vdd, bool enable)
{
int ret;
@@ -514,68 +515,56 @@
}
/* Voltage regulator initialization. */
-static void __init regulator_init(struct device *dev,
- const struct acpu_level *lvl)
+static void __cpuinit regulator_init(struct scalable *sc)
{
- int cpu, ret;
- struct scalable *sc;
- int vdd_mem, vdd_dig, vdd_core;
+ int ret, vdd_mem, vdd_dig, vdd_core;
- vdd_mem = calculate_vdd_mem(lvl);
- vdd_dig = calculate_vdd_dig(lvl);
+ vdd_mem = calculate_vdd_mem(drv.max_acpu_lvl);
+ vdd_dig = calculate_vdd_dig(drv.max_acpu_lvl);
- rpm_regulator_init(&drv.scalable[L2], VREG_HFPLL_A,
- drv.scalable[L2].vreg[VREG_HFPLL_A].max_vdd, false);
- rpm_regulator_init(&drv.scalable[L2], VREG_HFPLL_B,
- drv.scalable[L2].vreg[VREG_HFPLL_B].max_vdd, false);
+ rpm_regulator_init(sc, VREG_MEM, vdd_mem, true);
+ rpm_regulator_init(sc, VREG_DIG, vdd_dig, true);
+ rpm_regulator_init(sc, VREG_HFPLL_A,
+ sc->vreg[VREG_HFPLL_A].max_vdd, false);
+ rpm_regulator_init(sc, VREG_HFPLL_B,
+ sc->vreg[VREG_HFPLL_B].max_vdd, false);
- for_each_possible_cpu(cpu) {
- sc = &drv.scalable[cpu];
-
- rpm_regulator_init(sc, VREG_MEM, vdd_mem, true);
- rpm_regulator_init(sc, VREG_DIG, vdd_dig, true);
- rpm_regulator_init(sc, VREG_HFPLL_A,
- sc->vreg[VREG_HFPLL_A].max_vdd, false);
- rpm_regulator_init(sc, VREG_HFPLL_B,
- sc->vreg[VREG_HFPLL_B].max_vdd, false);
-
- /* Setup Krait CPU regulators and initial core voltage. */
- sc->vreg[VREG_CORE].reg = regulator_get(dev,
- sc->vreg[VREG_CORE].name);
- if (IS_ERR(sc->vreg[VREG_CORE].reg)) {
- dev_err(drv.dev, "regulator_get(%s) failed (%ld)\n",
- sc->vreg[VREG_CORE].name,
- PTR_ERR(sc->vreg[VREG_CORE].reg));
- BUG();
- }
- vdd_core = calculate_vdd_core(lvl);
- ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
- sc->vreg[VREG_CORE].max_vdd);
- if (ret) {
- dev_err(drv.dev, "regulator_set_voltage(%s) (%d)\n",
- sc->vreg[VREG_CORE].name, ret);
- BUG();
- }
- sc->vreg[VREG_CORE].cur_vdd = vdd_core;
- ret = regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg,
- sc->vreg[VREG_CORE].peak_ua);
- if (ret < 0) {
- dev_err(drv.dev, "regulator_set_optimum_mode(%s) failed"
- " (%d)\n", sc->vreg[VREG_CORE].name, ret);
- BUG();
- }
- ret = regulator_enable(sc->vreg[VREG_CORE].reg);
- if (ret) {
- dev_err(drv.dev, "regulator_enable(%s) failed (%d)\n",
- sc->vreg[VREG_CORE].name, ret);
- BUG();
- }
+ /* Setup Krait CPU regulators and initial core voltage. */
+ sc->vreg[VREG_CORE].reg = regulator_get(drv.dev,
+ sc->vreg[VREG_CORE].name);
+ if (IS_ERR(sc->vreg[VREG_CORE].reg)) {
+ dev_err(drv.dev, "regulator_get(%s) failed (%ld)\n",
+ sc->vreg[VREG_CORE].name,
+ PTR_ERR(sc->vreg[VREG_CORE].reg));
+ BUG();
+ }
+ vdd_core = calculate_vdd_core(drv.max_acpu_lvl);
+ ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
+ sc->vreg[VREG_CORE].max_vdd);
+ if (ret) {
+ dev_err(drv.dev, "regulator_set_voltage(%s) (%d)\n",
+ sc->vreg[VREG_CORE].name, ret);
+ BUG();
+ }
+ sc->vreg[VREG_CORE].cur_vdd = vdd_core;
+ ret = regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg,
+ sc->vreg[VREG_CORE].peak_ua);
+ if (ret < 0) {
+ dev_err(drv.dev, "regulator_set_optimum_mode(%s) failed (%d)\n",
+ sc->vreg[VREG_CORE].name, ret);
+ BUG();
+ }
+ ret = regulator_enable(sc->vreg[VREG_CORE].reg);
+ if (ret) {
+ dev_err(drv.dev, "regulator_enable(%s) failed (%d)\n",
+ sc->vreg[VREG_CORE].name, ret);
+ BUG();
}
}
/* Set initial rate for a given core. */
-static void __init init_clock_sources(struct scalable *sc,
- const struct core_speed *tgt_s)
+static void __cpuinit init_clock_sources(struct scalable *sc,
+ const struct core_speed *tgt_s)
{
u32 regval;
void __iomem *aux_reg;
@@ -604,19 +593,23 @@
sc->cur_speed = tgt_s;
}
-static void __init per_cpu_init(int cpu, const struct acpu_level *max_level)
+static void __cpuinit per_cpu_init(int cpu)
{
- drv.scalable[cpu].hfpll_base =
- ioremap(drv.scalable[cpu].hfpll_phys_base, SZ_32);
- BUG_ON(!drv.scalable[cpu].hfpll_base);
+ struct scalable *sc = &drv.scalable[cpu];
- init_clock_sources(&drv.scalable[cpu], &max_level->speed);
- drv.scalable[cpu].l2_vote = max_level->l2_level;
+ sc->hfpll_base = ioremap(sc->hfpll_phys_base, SZ_32);
+ BUG_ON(!sc->hfpll_base);
+
+ regulator_init(sc);
+
+ init_clock_sources(sc, &drv.max_acpu_lvl->speed);
+ sc->l2_vote = drv.max_acpu_lvl->l2_level;
+
+ sc->initialized = true;
}
/* Register with bus driver. */
-static void __init bus_init(struct msm_bus_scale_pdata *bus_scale_data,
- unsigned int init_bw)
+static void __init bus_init(struct msm_bus_scale_pdata *bus_scale_data)
{
int ret;
@@ -626,7 +619,8 @@
BUG();
}
- ret = msm_bus_scale_client_update_request(drv.bus_perf_client, init_bw);
+ ret = msm_bus_scale_client_update_request(drv.bus_perf_client,
+ drv.max_acpu_lvl->l2_level->bw_level);
if (ret)
dev_err(drv.dev, "initial bandwidth req failed (%d)\n", ret);
}
@@ -684,6 +678,10 @@
regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg, 0);
break;
case CPU_UP_PREPARE:
+ if (!sc->initialized) {
+ per_cpu_init(cpu);
+ break;
+ }
if (WARN_ON(!prev_khz[cpu]))
return NOTIFY_BAD;
rc = regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg,
@@ -722,10 +720,10 @@
tbl->vdd_core = 1150000;
}
-static const struct acpu_level __init *select_freq_plan(
- struct acpu_level *const *pvs_tbl, u32 qfprom_phys)
+static void __init select_freq_plan(struct acpu_level *const *pvs_tbl,
+ u32 qfprom_phys)
{
- const struct acpu_level *l, *max_acpu_level = NULL;
+ const struct acpu_level *l;
void __iomem *qfprom_base;
u32 pte_efuse, pvs, tbl_idx;
char *pvs_names[] = { "Slow", "Nominal", "Fast", "Unknown" };
@@ -772,12 +770,10 @@
/* Find the max supported scaling frequency. */
for (l = drv.acpu_freq_tbl; l->speed.khz != 0; l++)
if (l->use_for_scaling)
- max_acpu_level = l;
- BUG_ON(!max_acpu_level);
+ drv.max_acpu_lvl = l;
+ BUG_ON(!drv.max_acpu_lvl);
dev_info(drv.dev, "Max ACPU freq: %lu KHz\n",
- max_acpu_level->speed.khz);
-
- return max_acpu_level;
+ drv.max_acpu_lvl->speed.khz);
}
static struct acpuclk_data acpuclk_krait_data = {
@@ -790,24 +786,27 @@
int __init acpuclk_krait_init(struct device *dev,
const struct acpuclk_krait_params *params)
{
- const struct acpu_level *max_acpu_level;
+ struct scalable *l2;
int cpu;
drv.scalable = params->scalable;
drv.l2_freq_tbl = params->l2_freq_tbl;
drv.dev = dev;
- drv.scalable[L2].hfpll_base =
- ioremap(drv.scalable[L2].hfpll_phys_base, SZ_32);
- BUG_ON(!drv.scalable[L2].hfpll_base);
+ select_freq_plan(params->pvs_acpu_freq_tbl, params->qfprom_phys_base);
+ bus_init(params->bus_scale_data);
- max_acpu_level = select_freq_plan(params->pvs_acpu_freq_tbl,
- params->qfprom_phys_base);
- regulator_init(dev, max_acpu_level);
- bus_init(params->bus_scale_data, max_acpu_level->l2_level->bw_level);
- init_clock_sources(&drv.scalable[L2], &max_acpu_level->l2_level->speed);
+ l2 = &drv.scalable[L2];
+ l2->hfpll_base = ioremap(l2->hfpll_phys_base, SZ_32);
+ BUG_ON(!l2->hfpll_base);
+ rpm_regulator_init(l2, VREG_HFPLL_A, l2->vreg[VREG_HFPLL_A].max_vdd,
+ false);
+ rpm_regulator_init(l2, VREG_HFPLL_B, l2->vreg[VREG_HFPLL_B].max_vdd,
+ false);
+ init_clock_sources(l2, &drv.max_acpu_lvl->l2_level->speed);
+
for_each_online_cpu(cpu)
- per_cpu_init(cpu, max_acpu_level);
+ per_cpu_init(cpu);
cpufreq_table_init();