diff mbox

[PM-WIP-OPP,3/3,v2] DSPBRIDGE: pm: use pm-wip-opp APIs for opp list

Message ID 1271895479-27744-4-git-send-email-nm@ti.com (mailing list archive)
State New, archived
Delegated to: Kevin Hilman
Headers show

Commit Message

Nishanth Menon April 22, 2010, 12:17 a.m. UTC
None
diff mbox

Patch

diff --git a/arch/arm/mach-omap2/dspbridge.c b/arch/arm/mach-omap2/dspbridge.c
index 8527a48..b2d08dc 100644
--- a/arch/arm/mach-omap2/dspbridge.c
+++ b/arch/arm/mach-omap2/dspbridge.c
@@ -15,6 +15,20 @@ 
 
 #ifdef CONFIG_BRIDGE_DVFS
 #include <plat/omap-pm.h>
+#include <plat/opp.h>
+/*
+ * The DSP load balancer works on the following logic:
+ * Opp frequencies:
+ * 0 <---------> Freq 1 <------------> Freq 2 <---------> Freq 3
+ * DSP Thresholds for the frequencies:
+ * 0M<-------X-> Freq 1 <-------M--X-> Freq 2 <----M--X-> Freq 3
+ * Where, M is the minimal threshold and X is maximum threshold
+ *
+ * if from Freq x to Freq y; where x > y, transition happens on M
+ * if from Freq x to Freq y; where x < y, transition happens on X
+ */
+#define BRIDGE_THRESH_HIGH_PERCENT	95
+#define BRIDGE_THRESH_LOW_PERCENT	88
 #endif
 
 #include <dspbridge/host_os.h>
@@ -42,72 +56,90 @@  static struct dspbridge_platform_data dspbridge_pdata __initdata = {
 static int __init get_opp_table(struct dspbridge_platform_data *pdata)
 {
 #ifdef CONFIG_BRIDGE_DVFS
-	/*
-	 * TODO: The following code is a direct replacement
-	 * improvements are possible.
-	 * XXX: Does not support 3630
-	 */
+	int mpu_freqs;
+	int dsp_freqs;
 	int i;
-	/* legacy values for 3430 */
-	u32 vdd1_dsp_freq[6][4] = {
-		{0, 0, 0, 0},
-		/*OPP1*/
-		{0, 90000, 0, 86000},
-		/*OPP2*/
-		{0, 180000, 80000, 170000},
-		/*OPP3*/
-		{0, 360000, 160000, 340000},
-		/*OPP4*/
-		{0, 396000, 325000, 376000},
-		/*OPP5*/
-		{0, 430000, 355000, 430000},
-	};
-	struct omap_opp vdd1_rate_table_bridge[] = {
-		{0, 0, 0},
-		/*OPP1*/
-		{125000000, VDD1_OPP1, 0},
-		/*OPP2*/
-		{250000000, VDD1_OPP2, 0},
-		/*OPP3*/
-		{500000000, VDD1_OPP3, 0},
-		/*OPP4*/
-		{550000000, VDD1_OPP4, 0},
-		/*OPP5*/
-		{600000000, VDD1_OPP5, 0},
-	};
-	pdata->mpu_num_speeds = VDD1_OPP5;
-	pdata->mpu_speeds = kzalloc(sizeof(u32) * (pdata->mpu_num_speeds + 1),
+	struct omap_opp *opp;
+	unsigned long freq, old_rate;
+
+	mpu_freqs = opp_get_opp_count(OPP_MPU);
+	dsp_freqs = opp_get_opp_count(OPP_DSP);
+	if (mpu_freqs < 0 || dsp_freqs < 0 || mpu_freqs != dsp_freqs) {
+		pr_err("%s:mpu and dsp frequencies are inconsistent! "
+			"mpu_freqs=%d dsp_freqs=%d\n", __func__, mpu_freqs,
+			dsp_freqs);
+		return -EINVAL;
+	}
+	/* allocate memory if we have opps initialized */
+	pdata->mpu_speeds = kzalloc(sizeof(u32) * mpu_freqs,
 			GFP_KERNEL);
 	if (!pdata->mpu_speeds) {
-		pr_err("%s: unable to allocate memory for the mpu"
-		"frequencies\n", __func__);
+		pr_err("%s:unable to allocate memory for the mpu"
+			"frequencies\n", __func__);
 		return -ENOMEM;
 	}
-	pdata->dsp_num_speeds = VDD1_OPP5;
+	i = 0;
+	freq = 0;
+	while (!IS_ERR(opp = opp_find_freq_ceil(OPP_MPU, &freq))) {
+		pdata->mpu_speeds[i] = freq;
+		freq++;
+		i++;
+	}
+	pdata->mpu_num_speeds = mpu_freqs;
+	pdata->mpu_min_speed = pdata->mpu_speeds[0];
+	pdata->mpu_max_speed = pdata->mpu_speeds[mpu_freqs - 1];
+	/* need an initial terminator */
 	pdata->dsp_freq_table = kzalloc(
 			sizeof(struct dsp_shm_freq_table) *
-			(pdata->dsp_num_speeds + 1), GFP_KERNEL);
+			(dsp_freqs + 1), GFP_KERNEL);
 	if (!pdata->dsp_freq_table) {
 		pr_err("%s: unable to allocate memory for the dsp"
-		"frequencies\n", __func__);
-		kfree(pdata->mpu_speeds);
-		pdata->mpu_speeds = NULL;
+			"frequencies\n", __func__);
 		return -ENOMEM;
 	}
-	for (i = 0; i <= pdata->mpu_num_speeds; i++)
-		pdata->mpu_speeds[i] = vdd1_rate_table_bridge[i].rate;
-	pdata->mpu_max_speed = pdata->mpu_speeds[VDD1_OPP5];
-	pdata->mpu_min_speed = pdata->mpu_speeds[VDD1_OPP1];
-
-	for (i = 0; i <= pdata->dsp_num_speeds; i++) {
-		pdata->dsp_freq_table[i].u_volts =
-				vdd1_dsp_freq[i][0];
-		pdata->dsp_freq_table[i].dsp_freq = vdd1_dsp_freq[i][1];
-		pdata->dsp_freq_table[i].thresh_min_freq =
-			vdd1_dsp_freq[i][2];
-		pdata->dsp_freq_table[i].thresh_max_freq =
-			vdd1_dsp_freq[i][3];
+
+	i = 1;
+	freq = 0;
+	old_rate = 0;
+	/*
+	 * the freq table is in terms of khz.. so we need to
+	 * divide by 1000
+	 */
+	while (!IS_ERR(opp = opp_find_freq_ceil(OPP_DSP, &freq))) {
+		/* dsp frequencies are in khz */
+		u32 rate = freq / 1000;
+
+		/*
+		 * On certain 34xx silicons, certain OPPs are duplicated
+		 * for DSP - handle those by copying previous opp value
+		 */
+		if (rate == old_rate) {
+			memcpy(&pdata->dsp_freq_table[i],
+				&pdata->dsp_freq_table[i-1],
+				sizeof(struct dsp_shm_freq_table));
+		} else {
+			pdata->dsp_freq_table[i].dsp_freq = rate;
+			pdata->dsp_freq_table[i].u_volts =
+				opp_get_voltage(opp);
+			/*
+			 * min threshold:
+			 * NOTE: index 1 needs a min of 0! else no
+			 * scaling happens at DSP!
+			 */
+			pdata->dsp_freq_table[i].thresh_min_freq =
+				((old_rate * BRIDGE_THRESH_LOW_PERCENT) / 100);
+
+			/* max threshold */
+			pdata->dsp_freq_table[i].thresh_max_freq =
+				((rate * BRIDGE_THRESH_HIGH_PERCENT) / 100);
+		}
+		old_rate = rate;
+		freq++;
+		i++;
 	}
+	/* the last entry should map with maximum rate */
+	pdata->dsp_freq_table[i - 1].thresh_max_freq = old_rate;
+	pdata->dsp_num_speeds = dsp_freqs;
 #endif
 	return 0;
 }