Re: [PATCH v4 7/7] RFC: drm/panfrost: devfreq: Add support for 2 regulators

From: Nicolas Boichat
Date: Wed Feb 12 2020 - 03:49:21 EST


+Viresh Kumar +Stephen Boyd for clock advice.

On Fri, Feb 7, 2020 at 1:27 PM Nicolas Boichat <drinkcat@xxxxxxxxxxxx> wrote:
>
> The Bifrost GPU on MT8183 uses 2 regulators (core and SRAM) for
> devfreq, and provides OPP table with 2 sets of voltages.
>
> TODO: This is incomplete as we'll need add support for setting
> a pair of voltages as well.

So all we need for this to work (at least apparently, that is, I can
change frequency) is this:
https://lore.kernel.org/patchwork/patch/1192945/
(ah well, Viresh just replied, so, probably not, I'll check that out
and use the correct API)

But then there's a slight problem: panfrost_devfreq uses a bunch of
clk_get_rate calls, and the clock PLLs (at least on MTK platform) are
never fully precise, so we get back 299999955 for 300 Mhz and
799999878 for 800 Mhz. That means that the kernel is unable to keep
devfreq stats as neither of these values are in the table:
[ 4802.470952] devfreq devfreq1: Couldn't update frequency transition
information.
The kbase driver fixes this by remembering the last set frequency, and
reporting that to devfreq. Should we do that as well or is there a
better fix?

Another thing that I'm not implementing is the dance that Mediatek
does in their kbase driver when changing the clock (described in patch
2/7):
""
The binding we use with out-of-tree Mali drivers includes more
clocks, this is used for devfreq: the out-of-tree driver switches
clk_mux to clk_sub_parent (26Mhz), adjusts clk_main_parent, then
switches clk_mux back to clk_main_parent:
(see https://chromium.googlesource.com/chromiumos/third_party/kernel/+/chromeos-4.19/drivers/gpu/arm/midgard/platform/mediatek/mali_kbase_runtime_pm.c#423)
clocks =
<&topckgen CLK_TOP_MFGPLL_CK>,
<&topckgen CLK_TOP_MUX_MFG>,
<&clk26m>,
<&mfgcfg CLK_MFG_BG3D>;
clock-names =
"clk_main_parent",
"clk_mux",
"clk_sub_parent",
"subsys_mfg_cg";
""
Is there a clean/simple way to implement this in the clock
framework/device tree? Or should we implement something in the
panfrost driver?

Thanks!



>
> Signed-off-by: Nicolas Boichat <drinkcat@xxxxxxxxxxxx>
>
> ---
> drivers/gpu/drm/panfrost/panfrost_devfreq.c | 17 +++++++++++++++++
> drivers/gpu/drm/panfrost/panfrost_device.h | 1 +
> 2 files changed, 18 insertions(+)
>
> diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
> index 413987038fbfccb..9c0987a3d71c597 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
> @@ -79,6 +79,21 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
> struct devfreq *devfreq;
> struct thermal_cooling_device *cooling;
>
> + /* If we have 2 regulator, we need an OPP table with 2 voltages. */
> + if (pfdev->comp->num_supplies > 1) {
> + pfdev->devfreq.dev_opp_table =
> + dev_pm_opp_set_regulators(dev,
> + pfdev->comp->supply_names,
> + pfdev->comp->num_supplies);
> + if (IS_ERR(pfdev->devfreq.dev_opp_table)) {
> + ret = PTR_ERR(pfdev->devfreq.dev_opp_table);
> + pfdev->devfreq.dev_opp_table = NULL;
> + dev_err(dev,
> + "Failed to init devfreq opp table: %d\n", ret);
> + return ret;
> + }
> + }
> +
> ret = dev_pm_opp_of_add_table(dev);
> if (ret == -ENODEV) /* Optional, continue without devfreq */
> return 0;
> @@ -119,6 +134,8 @@ void panfrost_devfreq_fini(struct panfrost_device *pfdev)
> if (pfdev->devfreq.cooling)
> devfreq_cooling_unregister(pfdev->devfreq.cooling);
> dev_pm_opp_of_remove_table(&pfdev->pdev->dev);
> + if (pfdev->devfreq.dev_opp_table)
> + dev_pm_opp_put_regulators(pfdev->devfreq.dev_opp_table);
> }
>
> void panfrost_devfreq_resume(struct panfrost_device *pfdev)
> diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h
> index c30c719a805940a..5009a8b7c853ea1 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_device.h
> +++ b/drivers/gpu/drm/panfrost/panfrost_device.h
> @@ -110,6 +110,7 @@ struct panfrost_device {
> struct {
> struct devfreq *devfreq;
> struct thermal_cooling_device *cooling;
> + struct opp_table *dev_opp_table;
> ktime_t busy_time;
> ktime_t idle_time;
> ktime_t time_last_update;
> --
> 2.25.0.341.g760bfbb309-goog
>