CHROMIUM: Fix mali_devfreq for platform other than mediatek.

Move changes in CL:1317240 to runtime hooks instead, and add default
implementations.

BUG=b:121277411
TEST=CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 make \
       O=/tmp/allmod -j 40 allmodconfig && \
     CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 make \
       O=/tmp/allmod -j 40

Change-Id: Idc80c23bf8fa23657bdb910f9f0a73d11b5c8026
Signed-off-by: Pi-Hsun Shih <pihsun@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1424957
Commit-Ready: Douglas Anderson <dianders@chromium.org>
Reviewed-by: Dominik Behr <dbehr@chromium.org>
diff --git a/drivers/gpu/arm/midgard/Kconfig b/drivers/gpu/arm/midgard/Kconfig
index a327c30..6273f33 100644
--- a/drivers/gpu/arm/midgard/Kconfig
+++ b/drivers/gpu/arm/midgard/Kconfig
@@ -61,7 +61,6 @@
 config MALI_DEVFREQ
 	bool "devfreq support for Mali"
 	depends on MALI_MIDGARD && PM_DEVFREQ
-	depends on MALI_PLATFORM_NAME="mediatek"
 	default y
 	help
 	  Support devfreq for Mali.
diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c
index 683a24c..98f7d73 100644
--- a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c
+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c
@@ -79,6 +79,46 @@
 	return freq;
 }
 
+static void voltage_range_check(struct kbase_device *kbdev,
+				unsigned long *voltages)
+{
+	if (kbdev->devfreq_ops.voltage_range_check)
+		kbdev->devfreq_ops.voltage_range_check(kbdev, voltages);
+}
+
+#ifdef CONFIG_REGULATOR
+static int set_voltages(struct kbase_device *kbdev, unsigned long *voltages,
+			bool inc)
+{
+	int i;
+	int err;
+
+	if (kbdev->devfreq_ops.set_voltages)
+		return kbdev->devfreq_ops.set_voltages(kbdev, voltages, inc);
+
+	for (i = 0; i < kbdev->regulator_num; i++) {
+		err = regulator_set_voltage(kbdev->regulator[i],
+					    voltages[i], voltages[i]);
+		if (err) {
+			dev_err(kbdev->dev,
+				"Failed to set reg %d voltage err:(%d)\n",
+				i, err);
+			return err;
+		}
+	}
+
+	return 0;
+}
+#endif
+
+static int set_frequency(struct kbase_device *kbdev, unsigned long freq)
+{
+	if (kbdev->devfreq_ops.set_frequency)
+		return kbdev->devfreq_ops.set_frequency(kbdev, freq);
+
+	return clk_set_rate(kbdev->clock, freq);
+}
+
 static int
 kbase_devfreq_target(struct device *dev, unsigned long *target_freq, u32 flags)
 {
@@ -86,8 +126,8 @@
 	struct dev_pm_opp *opp;
 	unsigned long nominal_freq;
 	unsigned long freq = 0;
-	unsigned long voltage;
-	int err;
+	unsigned long target_volt[REGULATOR_NUM];
+	int err, i;
 	u64 core_mask;
 
 	freq = *target_freq;
@@ -96,7 +136,6 @@
 	rcu_read_lock();
 #endif
 	opp = devfreq_recommended_opp(dev, &freq, flags);
-	voltage = dev_pm_opp_get_voltage(opp);
 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
 	rcu_read_unlock();
 #endif
@@ -104,6 +143,9 @@
 		dev_err(dev, "Failed to get opp (%ld)\n", PTR_ERR(opp));
 		return PTR_ERR(opp);
 	}
+
+	for (i = 0; i < kbdev->regulator_num; i++)
+		target_volt[i] = dev_pm_opp_get_voltage_supply(opp, i);
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
 	dev_pm_opp_put(opp);
 #endif
@@ -113,24 +155,26 @@
 	/*
 	 * Only update if there is a change of frequency
 	 */
-	if (kbdev->current_nominal_freq == nominal_freq) {
+	if (kbdev->current_nominal_freq == nominal_freq &&
+		kbdev->current_voltage[0] == target_volt[0]) {
 		*target_freq = nominal_freq;
 		return 0;
 	}
 
 	freq = opp_translate(kbdev, nominal_freq, &core_mask);
+	voltage_range_check(kbdev, target_volt);
+
 #ifdef CONFIG_REGULATOR
-	if (kbdev->regulator && kbdev->current_voltage != voltage
-			&& kbdev->current_freq < freq) {
-		err = regulator_set_voltage(kbdev->regulator, voltage, voltage);
+	if (kbdev->current_voltage[0] < target_volt[0]) {
+		err = set_voltages(kbdev, target_volt, true);
 		if (err) {
-			dev_err(dev, "Failed to increase voltage (%d)\n", err);
+			dev_err(kbdev->dev, "Failed to increase voltage\n");
 			return err;
 		}
 	}
 #endif
 
-	err = clk_set_rate(kbdev->clock, freq);
+	err = set_frequency(kbdev, freq);
 	if (err) {
 		dev_err(dev, "Failed to set clock %lu (target %lu)\n",
 				freq, *target_freq);
@@ -138,11 +182,10 @@
 	}
 
 #ifdef CONFIG_REGULATOR
-	if (kbdev->regulator && kbdev->current_voltage != voltage
-			&& kbdev->current_freq > freq) {
-		err = regulator_set_voltage(kbdev->regulator, voltage, voltage);
+	if (kbdev->current_voltage[0] > target_volt[0]) {
+		err = set_voltages(kbdev, target_volt, false);
 		if (err) {
-			dev_err(dev, "Failed to decrease voltage (%d)\n", err);
+			dev_err(kbdev->dev, "Failed to decrease voltage\n");
 			return err;
 		}
 	}
@@ -151,7 +194,8 @@
 	kbase_devfreq_set_core_mask(kbdev, core_mask);
 
 	*target_freq = nominal_freq;
-	kbdev->current_voltage = voltage;
+	for (i = 0; i < kbdev->regulator_num; i++)
+		kbdev->current_voltage[i] = target_volt[i];
 	kbdev->current_nominal_freq = nominal_freq;
 	kbdev->current_freq = freq;
 	kbdev->current_core_mask = core_mask;
diff --git a/drivers/gpu/arm/midgard/mali_kbase_defs.h b/drivers/gpu/arm/midgard/mali_kbase_defs.h
index 6c978cc..1454755 100644
--- a/drivers/gpu/arm/midgard/mali_kbase_defs.h
+++ b/drivers/gpu/arm/midgard/mali_kbase_defs.h
@@ -1525,6 +1525,16 @@
 	struct kbase_devfreq_opp *opp_table;
 	int num_opps;
 	struct kbasep_pm_metrics last_devfreq_metrics;
+	struct {
+		void (*voltage_range_check)(struct kbase_device *kbdev,
+					    unsigned long *voltages);
+#ifdef CONFIG_REGULATOR
+		int (*set_voltages)(struct kbase_device *kbdev,
+				    unsigned long *voltages, bool inc);
+#endif
+		int (*set_frequency)(struct kbase_device *kbdev,
+				     unsigned long freq);
+	} devfreq_ops;
 #ifdef CONFIG_DEVFREQ_THERMAL
 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)
 	struct devfreq_cooling_device *devfreq_cooling;
diff --git a/drivers/gpu/arm/midgard/platform/mediatek/mali_kbase_runtime_pm.c b/drivers/gpu/arm/midgard/platform/mediatek/mali_kbase_runtime_pm.c
index 69bb2ce..0271ffc 100644
--- a/drivers/gpu/arm/midgard/platform/mediatek/mali_kbase_runtime_pm.c
+++ b/drivers/gpu/arm/midgard/platform/mediatek/mali_kbase_runtime_pm.c
@@ -308,6 +308,128 @@
 	}
 }
 
+static void voltage_range_check(struct kbase_device *kbdev,
+				unsigned long *voltages)
+{
+	if (voltages[1] - voltages[0] < MIN_VOLT_BIAS ||
+	    voltages[1] - voltages[0] > MAX_VOLT_BIAS)
+		voltages[1] = voltages[0] + MIN_VOLT_BIAS;
+	voltages[1] = clamp_t(unsigned long, voltages[1], VSRAM_GPU_MIN_VOLT,
+			      VSRAM_GPU_MAX_VOLT);
+}
+
+#ifdef CONFIG_REGULATOR
+static bool get_step_volt(unsigned long *step_volt, unsigned long *target_volt,
+			  int count, bool inc)
+{
+	unsigned long regulator_min_volt;
+	unsigned long regulator_max_volt;
+	unsigned long current_bias;
+	long adjust_step;
+	int i;
+
+	if (inc) {
+		current_bias = target_volt[1] - step_volt[0];
+		adjust_step = MIN_VOLT_BIAS;
+	} else {
+		current_bias = step_volt[1] - target_volt[0];
+		adjust_step = -MIN_VOLT_BIAS;
+	}
+
+	for (i = 0; i < count; ++i)
+		if (step_volt[i] != target_volt[i])
+			break;
+
+	if (i == count)
+		return 0;
+
+	for (i = 0; i < count; i++) {
+		if (i) {
+			regulator_min_volt = VSRAM_GPU_MIN_VOLT;
+			regulator_max_volt = VSRAM_GPU_MAX_VOLT;
+		} else {
+			regulator_min_volt = VGPU_MIN_VOLT;
+			regulator_max_volt = VGPU_MAX_VOLT;
+		}
+
+		if (current_bias > MAX_VOLT_BIAS) {
+			step_volt[i] = clamp_val(step_volt[0] + adjust_step,
+						 regulator_min_volt,
+						 regulator_max_volt);
+		} else {
+			step_volt[i] = target_volt[i];
+		}
+	}
+	return 1;
+}
+
+static int set_voltages(struct kbase_device *kbdev, unsigned long *voltages,
+			bool inc)
+{
+	unsigned long step_volt[REGULATOR_NUM];
+	int first, step;
+	int i;
+	int err;
+
+	for (i = 0; i < kbdev->regulator_num; ++i)
+		step_volt[i] = kbdev->current_voltage[i];
+
+	if (inc) {
+		first = kbdev->regulator_num - 1;
+		step = -1;
+	} else {
+		first = 0;
+		step = 1;
+	}
+
+	while (get_step_volt(step_volt, voltages, kbdev->regulator_num, inc)) {
+		for (i = first; i >= 0 && i < kbdev->regulator_num; i += step) {
+			if (kbdev->current_voltage[i] == step_volt[i])
+				continue;
+
+			err = regulator_set_voltage(kbdev->regulator[i],
+						    step_volt[i],
+						    step_volt[i] + VOLT_TOL);
+
+			if (err) {
+				dev_err(kbdev->dev,
+					"Failed to set reg %d voltage err:(%d)\n",
+					i, err);
+				return err;
+			}
+		}
+	}
+
+	return 0;
+}
+#endif
+
+static int set_frequency(struct kbase_device *kbdev, unsigned long freq)
+{
+	int err;
+	struct mfg_base *mfg = kbdev->platform_context;
+
+	if (kbdev->current_freq != freq) {
+		err = clk_set_parent(mfg->clk_mux, mfg->clk_sub_parent);
+		if (err) {
+			dev_err(kbdev->dev, "Failed to select sub clock src\n");
+			return err;
+		}
+
+		err = clk_set_rate(kbdev->clock, freq);
+		if (err)
+			return err;
+
+		err = clk_set_parent(mfg->clk_mux, mfg->clk_main_parent);
+		if (err) {
+			dev_err(kbdev->dev,
+				"Failed to select main clock src\n");
+			return err;
+		}
+	}
+
+	return 0;
+}
 
 static int platform_init(struct kbase_device *kbdev)
 {
@@ -344,7 +466,11 @@
 		goto platform_init_err;
 	}
 
-	return 0;
+	kbdev->devfreq_ops.set_frequency = set_frequency;
+#ifdef CONFIG_REGULATOR
+	kbdev->devfreq_ops.set_voltages = set_voltages;
+#endif
+	kbdev->devfreq_ops.voltage_range_check = voltage_range_check;
 
 platform_init_err:
 	kfree(mfg);
@@ -378,4 +504,3 @@
 }
 
 subsys_initcall(mtk_mfg_corex);
-