CHROMIUM: MALI: More properly handle missing regulators
The mali code makes some attempt to work without regulators but it's
definitely wonky. Let's clean it up. Specifically:
1. We'll use regulator_get() instead of regulator_get_optional().
This causes the regulator framework to create a dummy regulator for
us that we can safely enable/disable and is there specifically to
avoid the need for special cases like this. When the framework
creates a dummy it nicely prints to the logs so you're aware of it,
like: "ffa30000.gpu supply bogus not found, using dummy regulator"
2. We know regulator_get() won't return NULL so don't check for it.
The old code wouldn't have worked right if regulator_get_optional()
had returned NULL since the PTR_ERR() call below wouldn't have made
sense.
3. In general we don't want to print about EPROBE_DEFER errors, so
let's not do that. ...and, in fact, now that we're using
regulator_get() we no longer _expect_ any errors, so we end up
totally inverting the old "if" test for when to print errors.
4. If a regulator is missing (or was replaced with a dummy) then
dev_opp_table will fail to init. When that happened we didn't
crash but we'd keep spewing "core: dev_pm_opp_get_voltage_supply:
Invalid supply index" all the time. Let's fix it to just not init
devfreq in this case since (I believe) devfreq makes no real sense
without a regulator.
BUG=chromium:941638
TEST=devfreq works OK on veyron still
TEST=Add 'supply-names = "mali", "bogus";' to veyron and look at dmesg
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1544030
(cherry-picked from c335bdf220e40540fc0c5913f1e07fb43d986467)
[drinkcat: Rebased on r20p0:
- Significant core changes, we do not use the default regulator
names and fetch them from device tree instead.
- Point 3 is obsolete now (the core was properly checking for
EPROBE_DEFER, yeay!
- Restore opp_table check.
]
Change-Id: Id1d242908ee972f153651df525101b8c1a40434f
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 5c17297..6ad1581 100644
--- a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c
+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c
@@ -609,6 +609,12 @@
return -ENODEV;
}
+ /* Can't do devfreq without this table */
+ if (!kbdev->opp_table) {
+ dev_err(kbdev->dev, "Uninitialized devfreq opp table\n");
+ return -ENODEV;
+ }
+
for (i = 0; i < kbdev->nr_clocks; i++) {
if (kbdev->clocks[i])
kbdev->current_freqs[i] =
diff --git a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c
index a51698a..315ecfa 100644
--- a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c
+++ b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c
@@ -3418,37 +3418,53 @@
int err = 0;
unsigned int i;
#if defined(CONFIG_REGULATOR)
- static const char *regulator_names[] = {
- "mali", "shadercores"
- };
- BUILD_BUG_ON(ARRAY_SIZE(regulator_names) < BASE_MAX_NR_CLOCKS_REGULATORS);
+ const char *regulator_names[BASE_MAX_NR_CLOCKS_REGULATORS];
#endif /* CONFIG_REGULATOR */
if (!kbdev)
return -ENODEV;
+ kbdev->nr_regulators = of_property_count_strings(kbdev->dev->of_node,
+ "supply-names");
+
+ if (kbdev->nr_regulators > BASE_MAX_NR_CLOCKS_REGULATORS) {
+ dev_err(&pdev->dev, "Too many regulators: %d > %d\n",
+ kbdev->nr_regulators, BASE_MAX_NR_CLOCKS_REGULATORS);
+ return -EINVAL;
+ } else if (kbdev->nr_regulators == -EINVAL) {
+ /* The 'supply-names' is optional; if not there assume "mali" */
+ kbdev->nr_regulators = 1;
+ regulator_names[0] = "mali";
+ } else if (kbdev->nr_regulators < 0) {
+ err = kbdev->nr_regulators;
+ } else {
+ err = of_property_read_string_array(kbdev->dev->of_node,
+ "supply-names",
+ regulator_names,
+ kbdev->nr_regulators);
+ }
+
+ if (err < 0) {
+ dev_err(&pdev->dev, "Error reading supply-names: %d\n", err);
+ return err;
+ }
+
#if defined(CONFIG_REGULATOR)
/* Since the error code EPROBE_DEFER causes the entire probing
* procedure to be restarted from scratch at a later time,
* all regulators will be released before returning.
- *
- * Any other error is ignored and the driver will continue
- * operating with a partial initialization of regulators.
*/
- for (i = 0; i < BASE_MAX_NR_CLOCKS_REGULATORS; i++) {
- kbdev->regulators[i] = regulator_get_optional(kbdev->dev,
+ for (i = 0; i < kbdev->nr_regulators; i++) {
+ kbdev->regulators[i] = regulator_get(kbdev->dev,
regulator_names[i]);
- if (IS_ERR_OR_NULL(kbdev->regulators[i])) {
+ if (IS_ERR(kbdev->regulators[i])) {
err = PTR_ERR(kbdev->regulators[i]);
kbdev->regulators[i] = NULL;
- break;
+ if (err != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get regulator\n");
+ goto fail;
}
}
- if (err == -EPROBE_DEFER) {
- while ((i > 0) && (i < BASE_MAX_NR_CLOCKS_REGULATORS))
- regulator_put(kbdev->regulators[--i]);
- return err;
- }
kbdev->nr_regulators = i;
dev_dbg(&pdev->dev, "Regulators probed: %u\n", kbdev->nr_regulators);
@@ -3476,7 +3492,7 @@
while ((i > 0) && (i < BASE_MAX_NR_CLOCKS_REGULATORS)) {
clk_put(kbdev->clocks[i]);
}
- goto clocks_probe_defer;
+ goto fail;
}
kbdev->nr_clocks = i;
@@ -3499,6 +3515,12 @@
if (kbdev->nr_regulators > 0) {
kbdev->opp_table = dev_pm_opp_set_regulators(kbdev->dev,
regulator_names, BASE_MAX_NR_CLOCKS_REGULATORS);
+
+ if (IS_ERR(kbdev->opp_table)) {
+ kbdev->opp_table = NULL;
+ dev_err(kbdev->dev, "Failed to init devfreq opp table: %d\n",
+ PTR_ERR(kbdev->opp_table));
+ }
}
#endif /* (KERNEL_VERSION(4, 10, 0) <= LINUX_VERSION_CODE */
err = dev_pm_opp_of_add_table(kbdev->dev);
@@ -3508,7 +3530,7 @@
#endif /* KERNEL_VERSION(4, 4, 0) > LINUX_VERSION_CODE */
return 0;
-clocks_probe_defer:
+fail:
#if defined(CONFIG_REGULATOR)
for (i = 0; i < BASE_MAX_NR_CLOCKS_REGULATORS; i++)
regulator_put(kbdev->regulators[i]);