162 lines
5.1 KiB
Diff
162 lines
5.1 KiB
Diff
this patch is based on:
|
|
|
|
https://pastebin.com/kwNHAdhu
|
|
via: https://oftc.irclog.whitequark.org/panfrost/2022-05-09#30915485
|
|
|
|
as it is supposed to be an improved version of the older and known to
|
|
be broken gpu freq scaling code from cadmium
|
|
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
index acce9d02dba0..9641769c64d1 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
|
|
@@ -29,13 +29,34 @@ static int panfrost_devfreq_target(struct device *dev, unsigned long *freq,
|
|
u32 flags)
|
|
{
|
|
struct dev_pm_opp *opp;
|
|
+ struct panfrost_device *pfdev = dev_get_drvdata(dev);
|
|
+ int ret, err;
|
|
+ char needs_reparenting = pfdev->mtk_clk_mux != NULL;
|
|
|
|
opp = devfreq_recommended_opp(dev, freq, flags);
|
|
if (IS_ERR(opp))
|
|
return PTR_ERR(opp);
|
|
dev_pm_opp_put(opp);
|
|
|
|
- return dev_pm_opp_set_rate(dev, *freq);
|
|
+ if (needs_reparenting) {
|
|
+ err = clk_set_parent(pfdev->mtk_clk_mux, pfdev->mtk_clk_sub);
|
|
+ if (err) {
|
|
+ DRM_DEV_ERROR(dev, "Failed to select sub clock source\n");
|
|
+ return err;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = dev_pm_opp_set_rate(dev, *freq);
|
|
+
|
|
+ if (needs_reparenting) {
|
|
+ err = clk_set_parent(pfdev->mtk_clk_mux, pfdev->mtk_clk_parent);
|
|
+ if (err) {
|
|
+ DRM_DEV_ERROR(dev, "Failed to select main clock source\n");
|
|
+ return err;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
}
|
|
|
|
static void panfrost_devfreq_reset(struct panfrost_devfreq *pfdevfreq)
|
|
@@ -91,16 +112,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
|
|
struct devfreq *devfreq;
|
|
struct opp_table *opp_table;
|
|
struct thermal_cooling_device *cooling;
|
|
- struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
|
|
-
|
|
- if (pfdev->comp->num_supplies > 1) {
|
|
- /*
|
|
- * GPUs with more than 1 supply require platform-specific handling:
|
|
- * continue without devfreq
|
|
- */
|
|
- DRM_DEV_INFO(dev, "More than 1 supply is not supported yet\n");
|
|
- return 0;
|
|
- }
|
|
+ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
|
|
|
|
opp_table = dev_pm_opp_set_regulators(dev, pfdev->comp->supply_names,
|
|
pfdev->comp->num_supplies);
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
|
|
index a2a09c51eed7..b77d738c7fb8 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
|
|
@@ -67,6 +67,32 @@ static int panfrost_clk_init(struct panfrost_device *pfdev)
|
|
goto disable_clock;
|
|
}
|
|
|
|
+ pfdev->mtk_clk_mux = devm_clk_get_optional(pfdev->dev, "clk_mux");
|
|
+ if (pfdev->mtk_clk_mux) {
|
|
+ if (IS_ERR(pfdev->mtk_clk_mux)) {
|
|
+ dev_err(pfdev->dev, "get clk_mux failed %ld\n",
|
|
+ PTR_ERR(pfdev->mtk_clk_mux));
|
|
+ err = PTR_ERR(pfdev->mtk_clk_mux);
|
|
+ goto disable_clock;
|
|
+ }
|
|
+
|
|
+ pfdev->mtk_clk_parent = devm_clk_get(pfdev->dev, "clk_main_parent");
|
|
+ if (IS_ERR(pfdev->mtk_clk_parent)) {
|
|
+ dev_err(pfdev->dev, "get clk_main_parent failed %ld\n",
|
|
+ PTR_ERR(pfdev->mtk_clk_parent));
|
|
+ err = PTR_ERR(pfdev->mtk_clk_parent);
|
|
+ goto disable_clock;
|
|
+ }
|
|
+
|
|
+ pfdev->mtk_clk_sub = devm_clk_get(pfdev->dev, "clk_sub_parent");
|
|
+ if (IS_ERR(pfdev->mtk_clk_sub)) {
|
|
+ dev_err(pfdev->dev, "get clk_sub_parent failed %ld\n",
|
|
+ PTR_ERR(pfdev->mtk_clk_sub));
|
|
+ err = PTR_ERR(pfdev->mtk_clk_sub);
|
|
+ goto disable_clock;
|
|
+ }
|
|
+ }
|
|
+
|
|
return 0;
|
|
|
|
disable_clock:
|
|
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h
|
|
index 8b2cdb8c701d..410b6099fea9 100644
|
|
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
|
|
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
|
|
@@ -84,6 +84,9 @@ struct panfrost_device {
|
|
void __iomem *iomem;
|
|
struct clk *clock;
|
|
struct clk *bus_clock;
|
|
+ struct clk *mtk_clk_mux;
|
|
+ struct clk *mtk_clk_parent;
|
|
+ struct clk *mtk_clk_sub;
|
|
struct regulator_bulk_data *regulators;
|
|
struct reset_control *rstc;
|
|
/* pm_domains for devices with more than one. */
|
|
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
|
|
index 65df3a106cf5..a3534dd83a00 100644
|
|
--- a/drivers/opp/core.c
|
|
+++ b/drivers/opp/core.c
|
|
@@ -784,18 +784,15 @@ static int _generic_set_opp_regulator(struct opp_table *opp_table,
|
|
struct regulator *reg = opp_table->regulators[0];
|
|
struct dev_pm_opp *old_opp = opp_table->current_opp;
|
|
int ret;
|
|
-
|
|
- /* This function only supports single regulator per device */
|
|
- if (WARN_ON(opp_table->regulator_count > 1)) {
|
|
- dev_err(dev, "multiple regulators are not supported\n");
|
|
- return -EINVAL;
|
|
- }
|
|
+ unsigned i;
|
|
|
|
/* Scaling up? Scale voltage before frequency */
|
|
if (!scaling_down) {
|
|
- ret = _set_opp_voltage(dev, reg, opp->supplies);
|
|
- if (ret)
|
|
- goto restore_voltage;
|
|
+ for (i = 0; i < opp_table->regulator_count; i++) {
|
|
+ ret = _set_opp_voltage(dev, opp_table->regulators[i], &opp->supplies[i]);
|
|
+ if (ret)
|
|
+ goto restore_voltage;
|
|
+ }
|
|
}
|
|
|
|
/* Change frequency */
|
|
@@ -805,9 +802,11 @@ static int _generic_set_opp_regulator(struct opp_table *opp_table,
|
|
|
|
/* Scaling down? Scale voltage after frequency */
|
|
if (scaling_down) {
|
|
- ret = _set_opp_voltage(dev, reg, opp->supplies);
|
|
- if (ret)
|
|
- goto restore_freq;
|
|
+ for (i = 0; i < opp_table->regulator_count; i++) {
|
|
+ ret = _set_opp_voltage(dev, opp_table->regulators[i], &opp->supplies[i]);
|
|
+ if (ret)
|
|
+ goto restore_freq;
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
--
|