16
16
#include <linux/of_reserved_mem.h>
17
17
#include <linux/of_device.h>
18
18
#include <linux/platform_device.h>
19
+ #include <linux/pm_domain.h>
19
20
#include <linux/regmap.h>
20
21
#include <linux/remoteproc.h>
21
22
#include <linux/workqueue.h>
@@ -79,6 +80,8 @@ struct imx_rproc_mem {
79
80
#define ATT_OWN BIT(1)
80
81
#define ATT_IOMEM BIT(2)
81
82
83
+ static int imx_rproc_detach_pd (struct rproc * rproc );
84
+
82
85
struct imx_rproc {
83
86
struct device * dev ;
84
87
struct regmap * regmap ;
@@ -96,6 +99,10 @@ struct imx_rproc {
96
99
struct notifier_block rproc_nb ;
97
100
u32 rproc_pt ; /* partition id */
98
101
u32 rsrc_id ; /* resource id */
102
+ u32 entry ; /* cpu start address */
103
+ int num_pd ;
104
+ struct device * * pd_dev ;
105
+ struct device_link * * pd_dev_link ;
99
106
};
100
107
101
108
static const struct imx_rproc_att imx_rproc_att_imx93 [] = {
@@ -335,6 +342,9 @@ static int imx_rproc_start(struct rproc *rproc)
335
342
arm_smccc_smc (IMX_SIP_RPROC , IMX_SIP_RPROC_START , 0 , 0 , 0 , 0 , 0 , 0 , & res );
336
343
ret = res .a0 ;
337
344
break ;
345
+ case IMX_RPROC_SCU_API :
346
+ ret = imx_sc_pm_cpu_start (priv -> ipc_handle , priv -> rsrc_id , true, priv -> entry );
347
+ break ;
338
348
default :
339
349
return - EOPNOTSUPP ;
340
350
}
@@ -364,6 +374,9 @@ static int imx_rproc_stop(struct rproc *rproc)
364
374
if (res .a1 )
365
375
dev_info (dev , "Not in wfi, force stopped\n" );
366
376
break ;
377
+ case IMX_RPROC_SCU_API :
378
+ ret = imx_sc_pm_cpu_start (priv -> ipc_handle , priv -> rsrc_id , false, priv -> entry );
379
+ break ;
367
380
default :
368
381
return - EOPNOTSUPP ;
369
382
}
@@ -713,8 +726,10 @@ static void imx_rproc_put_scu(struct rproc *rproc)
713
726
if (dcfg -> method != IMX_RPROC_SCU_API )
714
727
return ;
715
728
716
- if (imx_sc_rm_is_resource_owned (priv -> ipc_handle , priv -> rsrc_id ))
729
+ if (imx_sc_rm_is_resource_owned (priv -> ipc_handle , priv -> rsrc_id )) {
730
+ imx_rproc_detach_pd (rproc );
717
731
return ;
732
+ }
718
733
719
734
imx_scu_irq_group_enable (IMX_SC_IRQ_GROUP_REBOOTED , BIT (priv -> rproc_pt ), false);
720
735
imx_scu_irq_unregister_notifier (& priv -> rproc_nb );
@@ -736,6 +751,77 @@ static int imx_rproc_partition_notify(struct notifier_block *nb,
736
751
return 0 ;
737
752
}
738
753
754
+ static int imx_rproc_attach_pd (struct imx_rproc * priv )
755
+ {
756
+ struct device * dev = priv -> dev ;
757
+ int ret , i ;
758
+
759
+ /*
760
+ * If there is only one power-domain entry, the platform driver framework
761
+ * will handle it, no need handle it in this driver.
762
+ */
763
+ priv -> num_pd = of_count_phandle_with_args (dev -> of_node , "power-domains" ,
764
+ "#power-domain-cells" );
765
+ if (priv -> num_pd <= 1 )
766
+ return 0 ;
767
+
768
+ priv -> pd_dev = devm_kmalloc_array (dev , priv -> num_pd , sizeof (* priv -> pd_dev ), GFP_KERNEL );
769
+ if (!priv -> pd_dev )
770
+ return - ENOMEM ;
771
+
772
+ priv -> pd_dev_link = devm_kmalloc_array (dev , priv -> num_pd , sizeof (* priv -> pd_dev_link ),
773
+ GFP_KERNEL );
774
+
775
+ if (!priv -> pd_dev_link )
776
+ return - ENOMEM ;
777
+
778
+ for (i = 0 ; i < priv -> num_pd ; i ++ ) {
779
+ priv -> pd_dev [i ] = dev_pm_domain_attach_by_id (dev , i );
780
+ if (IS_ERR (priv -> pd_dev [i ])) {
781
+ ret = PTR_ERR (priv -> pd_dev [i ]);
782
+ goto detach_pd ;
783
+ }
784
+
785
+ priv -> pd_dev_link [i ] = device_link_add (dev , priv -> pd_dev [i ], DL_FLAG_STATELESS |
786
+ DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE );
787
+ if (!priv -> pd_dev_link [i ]) {
788
+ dev_pm_domain_detach (priv -> pd_dev [i ], false);
789
+ ret = - EINVAL ;
790
+ goto detach_pd ;
791
+ }
792
+ }
793
+
794
+ return 0 ;
795
+
796
+ detach_pd :
797
+ while (-- i >= 0 ) {
798
+ device_link_del (priv -> pd_dev_link [i ]);
799
+ dev_pm_domain_detach (priv -> pd_dev [i ], false);
800
+ }
801
+
802
+ return ret ;
803
+ }
804
+
805
+ static int imx_rproc_detach_pd (struct rproc * rproc )
806
+ {
807
+ struct imx_rproc * priv = rproc -> priv ;
808
+ int i ;
809
+
810
+ /*
811
+ * If there is only one power-domain entry, the platform driver framework
812
+ * will handle it, no need handle it in this driver.
813
+ */
814
+ if (priv -> num_pd <= 1 )
815
+ return 0 ;
816
+
817
+ for (i = 0 ; i < priv -> num_pd ; i ++ ) {
818
+ device_link_del (priv -> pd_dev_link [i ]);
819
+ dev_pm_domain_detach (priv -> pd_dev [i ], false);
820
+ }
821
+
822
+ return 0 ;
823
+ }
824
+
739
825
static int imx_rproc_detect_mode (struct imx_rproc * priv )
740
826
{
741
827
struct regmap_config config = { .name = "imx-rproc" };
@@ -770,8 +856,12 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv)
770
856
* If Mcore resource is not owned by Acore partition, It is kicked by ROM,
771
857
* and Linux could only do IPC with Mcore and nothing else.
772
858
*/
773
- if (imx_sc_rm_is_resource_owned (priv -> ipc_handle , priv -> rsrc_id ))
774
- return 0 ;
859
+ if (imx_sc_rm_is_resource_owned (priv -> ipc_handle , priv -> rsrc_id )) {
860
+ if (of_property_read_u32 (dev -> of_node , "fsl,entry-address" , & priv -> entry ))
861
+ return - EINVAL ;
862
+
863
+ return imx_rproc_attach_pd (priv );
864
+ }
775
865
776
866
priv -> rproc -> state = RPROC_DETACHED ;
777
867
priv -> rproc -> recovery_disabled = true;
0 commit comments