lkml.org 
[lkml]   [2020]   [Nov]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v10 09/19] PM / devfreq: tegra30: Support interconnect and OPPs from device-tree
    Date
    This patch moves ACTMON driver away from generating OPP table by itself,
    transitioning it to use the table which comes from device-tree. This
    change breaks compatibility with older device-trees and brings support
    for the interconnect framework to the driver. This is a mandatory change
    which needs to be done in order to implement interconnect-based memory
    DVFS, i.e. device-trees need to be updated. Now ACTMON issues a memory
    bandwidth requests using dev_pm_opp_set_bw() instead of driving EMC clock
    rate directly.

    Tested-by: Peter Geis <pgwipeout@gmail.com>
    Tested-by: Nicolas Chauvet <kwizart@gmail.com>
    Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
    Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
    ---
    drivers/devfreq/tegra30-devfreq.c | 79 +++++++++++++++----------------
    1 file changed, 37 insertions(+), 42 deletions(-)

    diff --git a/drivers/devfreq/tegra30-devfreq.c b/drivers/devfreq/tegra30-devfreq.c
    index 38cc0d014738..145ef91ae092 100644
    --- a/drivers/devfreq/tegra30-devfreq.c
    +++ b/drivers/devfreq/tegra30-devfreq.c
    @@ -19,6 +19,8 @@
    #include <linux/reset.h>
    #include <linux/workqueue.h>

    +#include <soc/tegra/fuse.h>
    +
    #include "governor.h"

    #define ACTMON_GLB_STATUS 0x0
    @@ -155,6 +157,7 @@ struct tegra_devfreq_device {

    struct tegra_devfreq {
    struct devfreq *devfreq;
    + struct opp_table *opp_table;

    struct reset_control *reset;
    struct clk *clock;
    @@ -612,34 +615,19 @@ static void tegra_actmon_stop(struct tegra_devfreq *tegra)
    static int tegra_devfreq_target(struct device *dev, unsigned long *freq,
    u32 flags)
    {
    - struct tegra_devfreq *tegra = dev_get_drvdata(dev);
    - struct devfreq *devfreq = tegra->devfreq;
    struct dev_pm_opp *opp;
    - unsigned long rate;
    - int err;
    + int ret;

    opp = devfreq_recommended_opp(dev, freq, flags);
    if (IS_ERR(opp)) {
    dev_err(dev, "Failed to find opp for %lu Hz\n", *freq);
    return PTR_ERR(opp);
    }
    - rate = dev_pm_opp_get_freq(opp);
    - dev_pm_opp_put(opp);
    -
    - err = clk_set_min_rate(tegra->emc_clock, rate * KHZ);
    - if (err)
    - return err;
    -
    - err = clk_set_rate(tegra->emc_clock, 0);
    - if (err)
    - goto restore_min_rate;

    - return 0;
    -
    -restore_min_rate:
    - clk_set_min_rate(tegra->emc_clock, devfreq->previous_freq);
    + ret = dev_pm_opp_set_bw(dev, opp);
    + dev_pm_opp_put(opp);

    - return err;
    + return ret;
    }

    static int tegra_devfreq_get_dev_status(struct device *dev,
    @@ -655,7 +643,7 @@ static int tegra_devfreq_get_dev_status(struct device *dev,
    stat->private_data = tegra;

    /* The below are to be used by the other governors */
    - stat->current_frequency = cur_freq;
    + stat->current_frequency = cur_freq * KHZ;

    actmon_dev = &tegra->devices[MCALL];

    @@ -705,7 +693,12 @@ static int tegra_governor_get_target(struct devfreq *devfreq,
    target_freq = max(target_freq, dev->target_freq);
    }

    - *freq = target_freq;
    + /*
    + * tegra-devfreq driver operates with KHz units, while OPP table
    + * entries use Hz units. Hence we need to convert the units for the
    + * devfreq core.
    + */
    + *freq = target_freq * KHZ;

    return 0;
    }
    @@ -774,6 +767,7 @@ static struct devfreq_governor tegra_devfreq_governor = {

    static int tegra_devfreq_probe(struct platform_device *pdev)
    {
    + u32 hw_version = BIT(tegra_sku_info.soc_speedo_id);
    struct tegra_devfreq_device *dev;
    struct tegra_devfreq *tegra;
    struct devfreq *devfreq;
    @@ -822,11 +816,25 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
    return err;
    }

    + tegra->opp_table = dev_pm_opp_set_supported_hw(&pdev->dev,
    + &hw_version, 1);
    + err = PTR_ERR_OR_ZERO(tegra->opp_table);
    + if (err) {
    + dev_err(&pdev->dev, "Failed to set supported HW: %d\n", err);
    + return err;
    + }
    +
    + err = dev_pm_opp_of_add_table(&pdev->dev);
    + if (err) {
    + dev_err(&pdev->dev, "Failed to add OPP table: %d\n", err);
    + goto put_hw;
    + }
    +
    err = clk_prepare_enable(tegra->clock);
    if (err) {
    dev_err(&pdev->dev,
    "Failed to prepare and enable ACTMON clock\n");
    - return err;
    + goto remove_table;
    }

    err = reset_control_reset(tegra->reset);
    @@ -850,23 +858,6 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
    dev->regs = tegra->regs + dev->config->offset;
    }

    - for (rate = 0; rate <= tegra->max_freq * KHZ; rate++) {
    - rate = clk_round_rate(tegra->emc_clock, rate);
    -
    - if (rate < 0) {
    - dev_err(&pdev->dev,
    - "Failed to round clock rate: %ld\n", rate);
    - err = rate;
    - goto remove_opps;
    - }
    -
    - err = dev_pm_opp_add(&pdev->dev, rate / KHZ, 0);
    - if (err) {
    - dev_err(&pdev->dev, "Failed to add OPP: %d\n", err);
    - goto remove_opps;
    - }
    - }
    -
    platform_set_drvdata(pdev, tegra);

    tegra->clk_rate_change_nb.notifier_call = tegra_actmon_clk_notify_cb;
    @@ -882,7 +873,6 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
    }

    tegra_devfreq_profile.initial_freq = clk_get_rate(tegra->emc_clock);
    - tegra_devfreq_profile.initial_freq /= KHZ;

    devfreq = devfreq_add_device(&pdev->dev, &tegra_devfreq_profile,
    "tegra_actmon", NULL);
    @@ -902,6 +892,10 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
    reset_control_reset(tegra->reset);
    disable_clk:
    clk_disable_unprepare(tegra->clock);
    +remove_table:
    + dev_pm_opp_of_remove_table(&pdev->dev);
    +put_hw:
    + dev_pm_opp_put_supported_hw(tegra->opp_table);

    return err;
    }
    @@ -913,11 +907,12 @@ static int tegra_devfreq_remove(struct platform_device *pdev)
    devfreq_remove_device(tegra->devfreq);
    devfreq_remove_governor(&tegra_devfreq_governor);

    - dev_pm_opp_remove_all_dynamic(&pdev->dev);
    -
    reset_control_reset(tegra->reset);
    clk_disable_unprepare(tegra->clock);

    + dev_pm_opp_of_remove_table(&pdev->dev);
    + dev_pm_opp_put_supported_hw(tegra->opp_table);
    +
    return 0;
    }

    --
    2.29.2
    \
     
     \ /
      Last update: 2020-11-23 01:40    [W:7.672 / U:0.052 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site