9
9
#include <linux/iopoll.h>
10
10
#include <linux/kernel.h>
11
11
#include <linux/pm_domain.h>
12
+ #include <linux/pm_opp.h>
12
13
#include <linux/pm_runtime.h>
13
14
#include <linux/types.h>
14
15
#include <media/v4l2-mem2mem.h>
@@ -66,10 +67,9 @@ static void core_clks_disable(struct venus_core *core)
66
67
67
68
static int core_clks_set_rate (struct venus_core * core , unsigned long freq )
68
69
{
69
- struct clk * clk = core -> clks [0 ];
70
70
int ret ;
71
71
72
- ret = clk_set_rate ( clk , freq );
72
+ ret = dev_pm_opp_set_rate ( core -> dev , freq );
73
73
if (ret )
74
74
return ret ;
75
75
@@ -744,13 +744,16 @@ static int venc_power_v4(struct device *dev, int on)
744
744
745
745
static int vcodec_domains_get (struct device * dev )
746
746
{
747
+ int ret ;
748
+ struct opp_table * opp_table ;
749
+ struct device * * opp_virt_dev ;
747
750
struct venus_core * core = dev_get_drvdata (dev );
748
751
const struct venus_resources * res = core -> res ;
749
752
struct device * pd ;
750
753
unsigned int i ;
751
754
752
755
if (!res -> vcodec_pmdomains_num )
753
- return - ENODEV ;
756
+ goto skip_pmdomains ;
754
757
755
758
for (i = 0 ; i < res -> vcodec_pmdomains_num ; i ++ ) {
756
759
pd = dev_pm_domain_attach_by_name (dev ,
@@ -767,7 +770,41 @@ static int vcodec_domains_get(struct device *dev)
767
770
if (!core -> pd_dl_venus )
768
771
return - ENODEV ;
769
772
773
+ skip_pmdomains :
774
+ if (!core -> has_opp_table )
775
+ return 0 ;
776
+
777
+ /* Attach the power domain for setting performance state */
778
+ opp_table = dev_pm_opp_attach_genpd (dev , res -> opp_pmdomain , & opp_virt_dev );
779
+ if (IS_ERR (opp_table )) {
780
+ ret = PTR_ERR (opp_table );
781
+ goto opp_attach_err ;
782
+ }
783
+
784
+ core -> opp_pmdomain = * opp_virt_dev ;
785
+ core -> opp_dl_venus = device_link_add (dev , core -> opp_pmdomain ,
786
+ DL_FLAG_RPM_ACTIVE |
787
+ DL_FLAG_PM_RUNTIME |
788
+ DL_FLAG_STATELESS );
789
+ if (!core -> opp_dl_venus ) {
790
+ ret = - ENODEV ;
791
+ goto opp_dl_add_err ;
792
+ }
793
+
770
794
return 0 ;
795
+
796
+ opp_dl_add_err :
797
+ dev_pm_domain_detach (core -> opp_pmdomain , true);
798
+ opp_attach_err :
799
+ if (core -> pd_dl_venus ) {
800
+ device_link_del (core -> pd_dl_venus );
801
+ for (i = 0 ; i < res -> vcodec_pmdomains_num ; i ++ ) {
802
+ if (IS_ERR_OR_NULL (core -> pmdomains [i ]))
803
+ continue ;
804
+ dev_pm_domain_detach (core -> pmdomains [i ], true);
805
+ }
806
+ }
807
+ return ret ;
771
808
}
772
809
773
810
static void vcodec_domains_put (struct device * dev )
@@ -777,7 +814,7 @@ static void vcodec_domains_put(struct device *dev)
777
814
unsigned int i ;
778
815
779
816
if (!res -> vcodec_pmdomains_num )
780
- return ;
817
+ goto skip_pmdomains ;
781
818
782
819
if (core -> pd_dl_venus )
783
820
device_link_del (core -> pd_dl_venus );
@@ -787,6 +824,15 @@ static void vcodec_domains_put(struct device *dev)
787
824
continue ;
788
825
dev_pm_domain_detach (core -> pmdomains [i ], true);
789
826
}
827
+
828
+ skip_pmdomains :
829
+ if (!core -> has_opp_table )
830
+ return ;
831
+
832
+ if (core -> opp_dl_venus )
833
+ device_link_del (core -> opp_dl_venus );
834
+
835
+ dev_pm_domain_detach (core -> opp_pmdomain , true);
790
836
}
791
837
792
838
static int core_get_v4 (struct device * dev )
@@ -815,30 +861,62 @@ static int core_get_v4(struct device *dev)
815
861
if (legacy_binding )
816
862
return 0 ;
817
863
864
+ core -> opp_table = dev_pm_opp_set_clkname (dev , "core" );
865
+ if (IS_ERR (core -> opp_table ))
866
+ return PTR_ERR (core -> opp_table );
867
+
868
+ if (core -> res -> opp_pmdomain ) {
869
+ ret = dev_pm_opp_of_add_table (dev );
870
+ if (!ret ) {
871
+ core -> has_opp_table = true;
872
+ } else if (ret != - ENODEV ) {
873
+ dev_err (dev , "invalid OPP table in device tree\n" );
874
+ dev_pm_opp_put_clkname (core -> opp_table );
875
+ return ret ;
876
+ }
877
+ }
878
+
818
879
ret = vcodec_domains_get (dev );
819
- if (ret )
880
+ if (ret ) {
881
+ if (core -> has_opp_table )
882
+ dev_pm_opp_of_remove_table (dev );
883
+ dev_pm_opp_put_clkname (core -> opp_table );
820
884
return ret ;
885
+ }
821
886
822
887
return 0 ;
823
888
}
824
889
825
890
static void core_put_v4 (struct device * dev )
826
891
{
892
+ struct venus_core * core = dev_get_drvdata (dev );
893
+
827
894
if (legacy_binding )
828
895
return ;
829
896
830
897
vcodec_domains_put (dev );
898
+
899
+ if (core -> has_opp_table )
900
+ dev_pm_opp_of_remove_table (dev );
901
+ if (core -> opp_table )
902
+ dev_pm_opp_put_clkname (core -> opp_table );
903
+
831
904
}
832
905
833
906
static int core_power_v4 (struct device * dev , int on )
834
907
{
835
908
struct venus_core * core = dev_get_drvdata (dev );
836
909
int ret = 0 ;
837
910
838
- if (on == POWER_ON )
911
+ if (on == POWER_ON ) {
839
912
ret = core_clks_enable (core );
840
- else
913
+ } else {
914
+ /* Drop the performance state vote */
915
+ if (core -> opp_pmdomain )
916
+ dev_pm_opp_set_rate (dev , 0 );
917
+
841
918
core_clks_disable (core );
919
+ }
842
920
843
921
return ret ;
844
922
}
0 commit comments