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
156158struct 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)
612615static 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
645633static 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
775768static 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 );
903893disable_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