Skip to content

Commit 16e8b2a

Browse files
digetxchanwoochoi
authored andcommitted
PM / devfreq: tegra30: Support interconnect and OPPs from device-tree
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 <[email protected]> Tested-by: Nicolas Chauvet <[email protected]> Acked-by: Chanwoo Choi <[email protected]> Signed-off-by: Dmitry Osipenko <[email protected]> Signed-off-by: Chanwoo Choi <[email protected]>
1 parent afd589c commit 16e8b2a

File tree

1 file changed

+37
-42
lines changed

1 file changed

+37
-42
lines changed

drivers/devfreq/tegra30-devfreq.c

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include <linux/reset.h>
2020
#include <linux/workqueue.h>
2121

22+
#include <soc/tegra/fuse.h>
23+
2224
#include "governor.h"
2325

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

156158
struct tegra_devfreq {
157159
struct devfreq *devfreq;
160+
struct opp_table *opp_table;
158161

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

621621
opp = devfreq_recommended_opp(dev, freq, flags);
622622
if (IS_ERR(opp)) {
623623
dev_err(dev, "Failed to find opp for %lu Hz\n", *freq);
624624
return PTR_ERR(opp);
625625
}
626-
rate = dev_pm_opp_get_freq(opp);
627-
dev_pm_opp_put(opp);
628-
629-
err = clk_set_min_rate(tegra->emc_clock, rate * KHZ);
630-
if (err)
631-
return err;
632-
633-
err = clk_set_rate(tegra->emc_clock, 0);
634-
if (err)
635-
goto restore_min_rate;
636626

637-
return 0;
638-
639-
restore_min_rate:
640-
clk_set_min_rate(tegra->emc_clock, devfreq->previous_freq);
627+
ret = dev_pm_opp_set_bw(dev, opp);
628+
dev_pm_opp_put(opp);
641629

642-
return err;
630+
return ret;
643631
}
644632

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

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

660648
actmon_dev = &tegra->devices[MCALL];
661649

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

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

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

775768
static int tegra_devfreq_probe(struct platform_device *pdev)
776769
{
770+
u32 hw_version = BIT(tegra_sku_info.soc_speedo_id);
777771
struct tegra_devfreq_device *dev;
778772
struct tegra_devfreq *tegra;
779773
struct devfreq *devfreq;
@@ -822,11 +816,25 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
822816
return err;
823817
}
824818

819+
tegra->opp_table = dev_pm_opp_set_supported_hw(&pdev->dev,
820+
&hw_version, 1);
821+
err = PTR_ERR_OR_ZERO(tegra->opp_table);
822+
if (err) {
823+
dev_err(&pdev->dev, "Failed to set supported HW: %d\n", err);
824+
return err;
825+
}
826+
827+
err = dev_pm_opp_of_add_table(&pdev->dev);
828+
if (err) {
829+
dev_err(&pdev->dev, "Failed to add OPP table: %d\n", err);
830+
goto put_hw;
831+
}
832+
825833
err = clk_prepare_enable(tegra->clock);
826834
if (err) {
827835
dev_err(&pdev->dev,
828836
"Failed to prepare and enable ACTMON clock\n");
829-
return err;
837+
goto remove_table;
830838
}
831839

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

853-
for (rate = 0; rate <= tegra->max_freq * KHZ; rate++) {
854-
rate = clk_round_rate(tegra->emc_clock, rate);
855-
856-
if (rate < 0) {
857-
dev_err(&pdev->dev,
858-
"Failed to round clock rate: %ld\n", rate);
859-
err = rate;
860-
goto remove_opps;
861-
}
862-
863-
err = dev_pm_opp_add(&pdev->dev, rate / KHZ, 0);
864-
if (err) {
865-
dev_err(&pdev->dev, "Failed to add OPP: %d\n", err);
866-
goto remove_opps;
867-
}
868-
}
869-
870861
platform_set_drvdata(pdev, tegra);
871862

872863
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)
882873
}
883874

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

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

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

916-
dev_pm_opp_remove_all_dynamic(&pdev->dev);
917-
918910
reset_control_reset(tegra->reset);
919911
clk_disable_unprepare(tegra->clock);
920912

913+
dev_pm_opp_of_remove_table(&pdev->dev);
914+
dev_pm_opp_put_supported_hw(tegra->opp_table);
915+
921916
return 0;
922917
}
923918

0 commit comments

Comments
 (0)