#include <linux/of_reserved_mem.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/pm_domain.h>
 #include <linux/regmap.h>
 #include <linux/remoteproc.h>
 #include <linux/workqueue.h>
 #define ATT_OWN                BIT(1)
 #define ATT_IOMEM      BIT(2)
 
+static int imx_rproc_detach_pd(struct rproc *rproc);
+
 struct imx_rproc {
        struct device                   *dev;
        struct regmap                   *regmap;
        struct notifier_block           rproc_nb;
        u32                             rproc_pt;       /* partition id */
        u32                             rsrc_id;        /* resource id */
+       u32                             entry;          /* cpu start address */
+       int                             num_pd;
+       struct device                   **pd_dev;
+       struct device_link              **pd_dev_link;
 };
 
 static const struct imx_rproc_att imx_rproc_att_imx93[] = {
                arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res);
                ret = res.a0;
                break;
+       case IMX_RPROC_SCU_API:
+               ret = imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry);
+               break;
        default:
                return -EOPNOTSUPP;
        }
                if (res.a1)
                        dev_info(dev, "Not in wfi, force stopped\n");
                break;
+       case IMX_RPROC_SCU_API:
+               ret = imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, false, priv->entry);
+               break;
        default:
                return -EOPNOTSUPP;
        }
        if (dcfg->method != IMX_RPROC_SCU_API)
                return;
 
-       if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id))
+       if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id)) {
+               imx_rproc_detach_pd(rproc);
                return;
+       }
 
        imx_scu_irq_group_enable(IMX_SC_IRQ_GROUP_REBOOTED, BIT(priv->rproc_pt), false);
        imx_scu_irq_unregister_notifier(&priv->rproc_nb);
        return 0;
 }
 
+static int imx_rproc_attach_pd(struct imx_rproc *priv)
+{
+       struct device *dev = priv->dev;
+       int ret, i;
+
+       /*
+        * If there is only one power-domain entry, the platform driver framework
+        * will handle it, no need handle it in this driver.
+        */
+       priv->num_pd = of_count_phandle_with_args(dev->of_node, "power-domains",
+                                                 "#power-domain-cells");
+       if (priv->num_pd <= 1)
+               return 0;
+
+       priv->pd_dev = devm_kmalloc_array(dev, priv->num_pd, sizeof(*priv->pd_dev), GFP_KERNEL);
+       if (!priv->pd_dev)
+               return -ENOMEM;
+
+       priv->pd_dev_link = devm_kmalloc_array(dev, priv->num_pd, sizeof(*priv->pd_dev_link),
+                                              GFP_KERNEL);
+
+       if (!priv->pd_dev_link)
+               return -ENOMEM;
+
+       for (i = 0; i < priv->num_pd; i++) {
+               priv->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i);
+               if (IS_ERR(priv->pd_dev[i])) {
+                       ret = PTR_ERR(priv->pd_dev[i]);
+                       goto detach_pd;
+               }
+
+               priv->pd_dev_link[i] = device_link_add(dev, priv->pd_dev[i], DL_FLAG_STATELESS |
+                                                      DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
+               if (!priv->pd_dev_link[i]) {
+                       dev_pm_domain_detach(priv->pd_dev[i], false);
+                       ret = -EINVAL;
+                       goto detach_pd;
+               }
+       }
+
+       return 0;
+
+detach_pd:
+       while (--i >= 0) {
+               device_link_del(priv->pd_dev_link[i]);
+               dev_pm_domain_detach(priv->pd_dev[i], false);
+       }
+
+       return ret;
+}
+
+static int imx_rproc_detach_pd(struct rproc *rproc)
+{
+       struct imx_rproc *priv = rproc->priv;
+       int i;
+
+       /*
+        * If there is only one power-domain entry, the platform driver framework
+        * will handle it, no need handle it in this driver.
+        */
+       if (priv->num_pd <= 1)
+               return 0;
+
+       for (i = 0; i < priv->num_pd; i++) {
+               device_link_del(priv->pd_dev_link[i]);
+               dev_pm_domain_detach(priv->pd_dev[i], false);
+       }
+
+       return 0;
+}
+
 static int imx_rproc_detect_mode(struct imx_rproc *priv)
 {
        struct regmap_config config = { .name = "imx-rproc" };
                 * If Mcore resource is not owned by Acore partition, It is kicked by ROM,
                 * and Linux could only do IPC with Mcore and nothing else.
                 */
-               if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id))
-                       return 0;
+               if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id)) {
+                       if (of_property_read_u32(dev->of_node, "fsl,entry-address", &priv->entry))
+                               return -EINVAL;
+
+                       return imx_rproc_attach_pd(priv);
+               }
 
                priv->rproc->state = RPROC_DETACHED;
                priv->rproc->recovery_disabled = true;