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);
-