pmaports/device/testing/linux-postmarketos-mtk-mt8183/mt8183-cadmium-improved-kukui.opp-multi-regulator.patch

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;
+ }
}
/*
--