CHROMIUM: MALI: Better framework to allow platform code to override devfreq
Depending on the platform, we require custom logic to handle devfreq.
The framework we used on r14p0 used 3 functions pointers, but we
can use a single one now (accepting a little bit of code duplication).
BUG=b:149806107
TEST=build kukui
Change-Id: I3b19abed242e5c1ca95338eafc93c4a35a5547b6
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
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 6ad1581..e42fa23 100644
--- a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c
+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c
@@ -92,6 +92,83 @@
}
static int
+default_set_freqs_volts(struct kbase_device *kbdev,
+ unsigned long *freqs, unsigned long *volts)
+{
+ unsigned int i;
+
+#ifdef CONFIG_REGULATOR
+ /* Regulators and clocks work in pairs: every clock has a regulator,
+ * and we never expect to have more regulators than clocks.
+ *
+ * We always need to increase the voltage before increasing
+ * the frequency of a regulator/clock pair, otherwise the clock
+ * wouldn't have enough power to perform the transition.
+ *
+ * It's always safer to decrease the frequency before decreasing
+ * voltage of a regulator/clock pair, otherwise the clock could have
+ * problems operating if it is deprived of the necessary power
+ * to sustain its current frequency (even if that happens for a short
+ * transition interval).
+ */
+ for (i = 0; i < kbdev->nr_clocks; i++) {
+ if (kbdev->regulators[i] &&
+ kbdev->current_voltages[i] != volts[i] &&
+ kbdev->current_freqs[i] < freqs[i]) {
+ int err;
+
+ err = regulator_set_voltage(kbdev->regulators[i],
+ volts[i], volts[i]);
+ if (!err) {
+ kbdev->current_voltages[i] = volts[i];
+ } else {
+ dev_err(kbdev->dev, "Failed to increase voltage (%d) (target %lu)\n",
+ err, volts[i]);
+ return err;
+ }
+ }
+ }
+#endif
+
+ for (i = 0; i < kbdev->nr_clocks; i++) {
+ if (kbdev->clocks[i]) {
+ int err;
+
+ err = clk_set_rate(kbdev->clocks[i], freqs[i]);
+ if (!err) {
+ kbdev->current_freqs[i] = freqs[i];
+ } else {
+ dev_err(kbdev->dev, "Failed to set clock %d to %lu\n",
+ i, freqs[i]);
+ return err;
+ }
+ }
+ }
+
+#ifdef CONFIG_REGULATOR
+ for (i = 0; i < kbdev->nr_clocks; i++) {
+ if (kbdev->regulators[i] &&
+ kbdev->current_voltages[i] != volts[i] &&
+ kbdev->current_freqs[i] > freqs[i]) {
+ int err;
+
+ err = regulator_set_voltage(kbdev->regulators[i],
+ volts[i], volts[i]);
+ if (!err) {
+ kbdev->current_voltages[i] = volts[i];
+ } else {
+ dev_err(kbdev->dev, "Failed to decrease voltage (%d) (target %lu)\n",
+ err, volts[i]);
+ return err;
+ }
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static int
kbase_devfreq_target(struct device *dev, unsigned long *target_freq, u32 flags)
{
struct kbase_device *kbdev = dev_get_drvdata(dev);
@@ -99,7 +176,7 @@
unsigned long nominal_freq;
unsigned long freqs[BASE_MAX_NR_CLOCKS_REGULATORS] = {0};
unsigned long volts[BASE_MAX_NR_CLOCKS_REGULATORS] = {0};
- unsigned int i;
+ int err;
u64 core_mask;
nominal_freq = *target_freq;
@@ -129,73 +206,12 @@
opp_translate(kbdev, nominal_freq, &core_mask, freqs, volts);
-#ifdef CONFIG_REGULATOR
- /* Regulators and clocks work in pairs: every clock has a regulator,
- * and we never expect to have more regulators than clocks.
- *
- * We always need to increase the voltage before increasing
- * the frequency of a regulator/clock pair, otherwise the clock
- * wouldn't have enough power to perform the transition.
- *
- * It's always safer to decrease the frequency before decreasing
- * voltage of a regulator/clock pair, otherwise the clock could have
- * problems operating if it is deprived of the necessary power
- * to sustain its current frequency (even if that happens for a short
- * transition interval).
- */
- for (i = 0; i < kbdev->nr_clocks; i++) {
- if (kbdev->regulators[i] &&
- kbdev->current_voltages[i] != volts[i] &&
- kbdev->current_freqs[i] < freqs[i]) {
- int err;
-
- err = regulator_set_voltage(kbdev->regulators[i],
- volts[i], volts[i]);
- if (!err) {
- kbdev->current_voltages[i] = volts[i];
- } else {
- dev_err(dev, "Failed to increase voltage (%d) (target %lu)\n",
- err, volts[i]);
- return err;
- }
- }
- }
-#endif
-
- for (i = 0; i < kbdev->nr_clocks; i++) {
- if (kbdev->clocks[i]) {
- int err;
-
- err = clk_set_rate(kbdev->clocks[i], freqs[i]);
- if (!err) {
- kbdev->current_freqs[i] = freqs[i];
- } else {
- dev_err(dev, "Failed to set clock %lu (target %lu)\n",
- freqs[i], *target_freq);
- return err;
- }
- }
- }
-
-#ifdef CONFIG_REGULATOR
- for (i = 0; i < kbdev->nr_clocks; i++) {
- if (kbdev->regulators[i] &&
- kbdev->current_voltages[i] != volts[i] &&
- kbdev->current_freqs[i] > freqs[i]) {
- int err;
-
- err = regulator_set_voltage(kbdev->regulators[i],
- volts[i], volts[i]);
- if (!err) {
- kbdev->current_voltages[i] = volts[i];
- } else {
- dev_err(dev, "Failed to decrease voltage (%d) (target %lu)\n",
- err, volts[i]);
- return err;
- }
- }
- }
-#endif
+ if (kbdev->devfreq_set_freqs_volts)
+ err = kbdev->devfreq_set_freqs_volts(kbdev, freqs, volts);
+ else
+ err = default_set_freqs_volts(kbdev, freqs, volts);
+ if (err < 0)
+ return err;
kbase_devfreq_set_core_mask(kbdev, core_mask);
diff --git a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c
index 315ecfa..d442f3a 100644
--- a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c
+++ b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c
@@ -3471,7 +3471,8 @@
#endif
/* Having more clocks than regulators is acceptable, while the
- * opposite shall not happen.
+ * opposite shall not happen, unless the platform code has
+ * a special handler for devfreq.
*
* Since the error code EPROBE_DEFER causes the entire probing
* procedure to be restarted from scratch at a later time,
diff --git a/drivers/gpu/arm/midgard/mali_kbase_defs.h b/drivers/gpu/arm/midgard/mali_kbase_defs.h
index ca73872..c63330b 100644
--- a/drivers/gpu/arm/midgard/mali_kbase_defs.h
+++ b/drivers/gpu/arm/midgard/mali_kbase_defs.h
@@ -1627,6 +1627,15 @@
struct kbase_devfreq_queue_info devfreq_queue;
#endif
+ /*
+ * An optional callback to set frequencies and voltages, if a custom
+ * implementation is required by the chip.
+ *
+ * This function needs to update kbdev->current_voltages/freqs.
+ */
+ int (*devfreq_set_freqs_volts)(struct kbase_device *kbdev,
+ unsigned long *freqs, unsigned long *volts);
+
#ifdef CONFIG_DEVFREQ_THERMAL
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)
struct devfreq_cooling_device *devfreq_cooling;