Merge "msm: acpuclock-8960: Support booting with fewer CPUs" into msm-3.4
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 6c14efa..9809bdf 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -154,6 +154,8 @@
 	struct l2_level *l2_vote;
 	struct vreg vreg[NUM_VREG];
 	unsigned int *hfpll_vdd_tbl;
+	bool regulators_initialized;
+	bool clocks_initialized;
 };
 
 static unsigned int hfpll_vdd_tbl_8960[] = {
@@ -842,6 +844,8 @@
 	[PVS_FAST] = acpu_freq_tbl_8930_fast,
 };
 
+static struct acpu_level *max_acpu_level;
+
 static unsigned long acpuclk_8960_get_rate(int cpu)
 {
 	return scalable[cpu].current_speed->khz;
@@ -1305,7 +1309,7 @@
 }
 
 /* Initialize a HFPLL at a given rate and enable it. */
-static void __init hfpll_init(struct scalable *sc, struct core_speed *tgt_s)
+static void __cpuinit hfpll_init(struct scalable *sc, struct core_speed *tgt_s)
 {
 	pr_debug("Initializing HFPLL%d\n", sc - scalable);
 
@@ -1326,69 +1330,66 @@
 }
 
 /* Voltage regulator initialization. */
-static void __init regulator_init(struct acpu_level *lvl)
+static void __cpuinit regulator_init(int cpu, struct acpu_level *lvl)
 {
-	int cpu, ret;
-	struct scalable *sc;
+	int ret;
+	struct scalable *sc = &scalable[cpu];
 	unsigned int vdd_mem, vdd_dig, vdd_core;
 
 	vdd_mem = calculate_vdd_mem(lvl);
 	vdd_dig = calculate_vdd_dig(lvl);
 
-	for_each_possible_cpu(cpu) {
-		sc = &scalable[cpu];
-
-		/* Set initial vdd_mem vote. */
-		ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
-				sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
-				sc->vreg[VREG_MEM].max_vdd, 0);
-		if (ret) {
-			pr_err("%s initialization failed (%d)\n",
-				sc->vreg[VREG_MEM].name, ret);
-			BUG();
-		}
-		sc->vreg[VREG_MEM].cur_vdd  = vdd_mem;
-
-		/* Set initial vdd_dig vote. */
-		ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
-				sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
-				sc->vreg[VREG_DIG].max_vdd, 0);
-		if (ret) {
-			pr_err("%s initialization failed (%d)\n",
-				sc->vreg[VREG_DIG].name, ret);
-			BUG();
-		}
-		sc->vreg[VREG_DIG].cur_vdd  = vdd_dig;
-
-		/* Setup Krait CPU regulators and initial core voltage. */
-		sc->vreg[VREG_CORE].reg = regulator_get(NULL,
-					  sc->vreg[VREG_CORE].name);
-		if (IS_ERR(sc->vreg[VREG_CORE].reg)) {
-			pr_err("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) {
-			pr_err("%s initialization failed (%d)\n",
-				sc->vreg[VREG_CORE].name, ret);
-			BUG();
-		}
-		sc->vreg[VREG_CORE].cur_vdd = vdd_core;
-		ret = regulator_enable(sc->vreg[VREG_CORE].reg);
-		if (ret) {
-			pr_err("regulator_enable(%s) failed (%d)\n",
-			       sc->vreg[VREG_CORE].name, ret);
-			BUG();
-		}
+	/* Set initial vdd_mem vote. */
+	ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
+			sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
+			sc->vreg[VREG_MEM].max_vdd, 0);
+	if (ret) {
+		pr_err("%s initialization failed (%d)\n",
+			sc->vreg[VREG_MEM].name, ret);
+		BUG();
 	}
+	sc->vreg[VREG_MEM].cur_vdd  = vdd_mem;
+
+	/* Set initial vdd_dig vote. */
+	ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
+			sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
+			sc->vreg[VREG_DIG].max_vdd, 0);
+	if (ret) {
+		pr_err("%s initialization failed (%d)\n",
+			sc->vreg[VREG_DIG].name, ret);
+		BUG();
+	}
+	sc->vreg[VREG_DIG].cur_vdd  = vdd_dig;
+
+	/* Setup Krait CPU regulators and initial core voltage. */
+	sc->vreg[VREG_CORE].reg = regulator_get(NULL,
+				  sc->vreg[VREG_CORE].name);
+	if (IS_ERR(sc->vreg[VREG_CORE].reg)) {
+		pr_err("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) {
+		pr_err("%s initialization failed (%d)\n",
+			sc->vreg[VREG_CORE].name, ret);
+		BUG();
+	}
+	sc->vreg[VREG_CORE].cur_vdd = vdd_core;
+	ret = regulator_enable(sc->vreg[VREG_CORE].reg);
+	if (ret) {
+		pr_err("regulator_enable(%s) failed (%d)\n",
+		       sc->vreg[VREG_CORE].name, ret);
+		BUG();
+	}
+	sc->regulators_initialized = true;
 }
 
 /* Set initial rate for a given core. */
-static void __init init_clock_sources(struct scalable *sc,
+static void __cpuinit init_clock_sources(struct scalable *sc,
 				      struct core_speed *tgt_s)
 {
 	uint32_t regval;
@@ -1412,13 +1413,13 @@
 	sc->current_speed = tgt_s;
 }
 
-static void __init per_cpu_init(void *data)
+static void __cpuinit per_cpu_init(void *data)
 {
-	struct acpu_level *max_acpu_level = data;
 	int cpu = smp_processor_id();
 
 	init_clock_sources(&scalable[cpu], &max_acpu_level->speed);
 	scalable[cpu].l2_vote = max_acpu_level->l2_level;
+	scalable[cpu].clocks_initialized = true;
 }
 
 /* Register with bus driver. */
@@ -1502,17 +1503,23 @@
 		/* Fall through. */
 	case CPU_UP_CANCELED:
 	case CPU_UP_CANCELED_FROZEN:
-		acpuclk_8960_set_rate(cpu, HOT_UNPLUG_KHZ, SETRATE_HOTPLUG);
+		if (scalable[cpu].clocks_initialized)
+			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]))
-			return NOTIFY_BAD;
-		acpuclk_8960_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
+		if (scalable[cpu].clocks_initialized)
+			acpuclk_8960_set_rate(cpu, prev_khz[cpu],
+					      SETRATE_HOTPLUG);
+		if (!scalable[cpu].regulators_initialized)
+			regulator_init(cpu, max_acpu_level);
 		break;
 	case CPU_STARTING:
 	case CPU_STARTING_FROZEN:
-		if (cpu_is_krait_v1() || cpu_is_apq8064()) {
+		if (!scalable[cpu].clocks_initialized) {
+			per_cpu_init(NULL);
+		} else if (cpu_is_krait_v1() || cpu_is_apq8064()) {
 			set_sec_clk_src(&scalable[cpu], prev_sec_src[cpu]);
 			set_pri_clk_src(&scalable[cpu], prev_pri_src[cpu]);
 		}
@@ -1578,9 +1585,9 @@
 	}
 }
 
-static struct acpu_level * __init select_freq_plan(void)
+static void __init select_freq_plan(void)
 {
-	struct acpu_level *l, *max_acpu_level = NULL;
+	struct acpu_level *l;
 
 	/* Select frequency tables. */
 	if (cpu_is_msm8960()) {
@@ -1628,8 +1635,6 @@
 			max_acpu_level = l;
 	BUG_ON(!max_acpu_level);
 	pr_info("Max ACPU freq: %u KHz\n", max_acpu_level->speed.khz);
-
-	return max_acpu_level;
 }
 
 static struct acpuclk_data acpuclk_8960_data = {
@@ -1641,13 +1646,16 @@
 
 static int __init acpuclk_8960_probe(struct platform_device *pdev)
 {
-	struct acpu_level *max_acpu_level = select_freq_plan();
+	int cpu;
 
-	regulator_init(max_acpu_level);
+	select_freq_plan();
+
+	for_each_online_cpu(cpu)
+		regulator_init(cpu, max_acpu_level);
 	bus_init(max_acpu_level->l2_level->bw_level);
 
 	init_clock_sources(&scalable[L2], &max_acpu_level->l2_level->speed);
-	on_each_cpu(per_cpu_init, max_acpu_level, true);
+	on_each_cpu(per_cpu_init, NULL, true);
 
 	cpufreq_table_init();