99#include <linux/iopoll.h>
1010#include <linux/kernel.h>
1111#include <linux/pm_domain.h>
12+ #include <linux/pm_opp.h>
1213#include <linux/pm_runtime.h>
1314#include <linux/types.h>
1415#include <media/v4l2-mem2mem.h>
@@ -66,10 +67,9 @@ static void core_clks_disable(struct venus_core *core)
6667
6768static int core_clks_set_rate (struct venus_core * core , unsigned long freq )
6869{
69- struct clk * clk = core -> clks [0 ];
7070 int ret ;
7171
72- ret = clk_set_rate ( clk , freq );
72+ ret = dev_pm_opp_set_rate ( core -> dev , freq );
7373 if (ret )
7474 return ret ;
7575
@@ -744,13 +744,16 @@ static int venc_power_v4(struct device *dev, int on)
744744
745745static int vcodec_domains_get (struct device * dev )
746746{
747+ int ret ;
748+ struct opp_table * opp_table ;
749+ struct device * * opp_virt_dev ;
747750 struct venus_core * core = dev_get_drvdata (dev );
748751 const struct venus_resources * res = core -> res ;
749752 struct device * pd ;
750753 unsigned int i ;
751754
752755 if (!res -> vcodec_pmdomains_num )
753- return - ENODEV ;
756+ goto skip_pmdomains ;
754757
755758 for (i = 0 ; i < res -> vcodec_pmdomains_num ; i ++ ) {
756759 pd = dev_pm_domain_attach_by_name (dev ,
@@ -767,7 +770,41 @@ static int vcodec_domains_get(struct device *dev)
767770 if (!core -> pd_dl_venus )
768771 return - ENODEV ;
769772
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+
770794 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 ;
771808}
772809
773810static void vcodec_domains_put (struct device * dev )
@@ -777,7 +814,7 @@ static void vcodec_domains_put(struct device *dev)
777814 unsigned int i ;
778815
779816 if (!res -> vcodec_pmdomains_num )
780- return ;
817+ goto skip_pmdomains ;
781818
782819 if (core -> pd_dl_venus )
783820 device_link_del (core -> pd_dl_venus );
@@ -787,6 +824,15 @@ static void vcodec_domains_put(struct device *dev)
787824 continue ;
788825 dev_pm_domain_detach (core -> pmdomains [i ], true);
789826 }
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);
790836}
791837
792838static int core_get_v4 (struct device * dev )
@@ -815,30 +861,62 @@ static int core_get_v4(struct device *dev)
815861 if (legacy_binding )
816862 return 0 ;
817863
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+
818879 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 );
820884 return ret ;
885+ }
821886
822887 return 0 ;
823888}
824889
825890static void core_put_v4 (struct device * dev )
826891{
892+ struct venus_core * core = dev_get_drvdata (dev );
893+
827894 if (legacy_binding )
828895 return ;
829896
830897 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+
831904}
832905
833906static int core_power_v4 (struct device * dev , int on )
834907{
835908 struct venus_core * core = dev_get_drvdata (dev );
836909 int ret = 0 ;
837910
838- if (on == POWER_ON )
911+ if (on == POWER_ON ) {
839912 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+
841918 core_clks_disable (core );
919+ }
842920
843921 return ret ;
844922}
0 commit comments