@@ -16,6 +16,7 @@
#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>
@@ -96,6 +97,10 @@ struct imx_rproc {
struct notifier_block proc_nb;
u32 rproc_pt; /* partition id */
u32 rsrc; /* 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_imx8qxp[] = {
@@ -304,6 +309,9 @@ static int imx_rproc_start(struct rproc *rproc)
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, true, priv->entry);
+ break;
default:
return -EOPNOTSUPP;
}
@@ -333,6 +341,9 @@ static int imx_rproc_stop(struct rproc *rproc)
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, false, priv->entry);
+ break;
default:
return -EOPNOTSUPP;
}
@@ -703,6 +714,56 @@ static int imx_rproc_partition_notify(struct notifier_block *nb,
return 0;
}
+static int imx_rproc_attach_pd(struct imx_rproc *priv)
+{
+ struct device *dev = priv->dev;
+ int ret, i;
+
+ priv->num_pd = of_count_phandle_with_args(dev->of_node, "power-domains",
+ "#power-domain-cells");
+ if (priv->num_pd < 0)
+ return priv->num_pd;
+
+ if (!priv->num_pd)
+ 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_detect_mode(struct imx_rproc *priv)
{
struct regmap_config config = { .name = "imx-rproc" };
@@ -737,8 +798,12 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv)
* 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))
- return 0;
+ if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc)) {
+ if (of_property_read_u32(dev->of_node, "entry", &priv->entry))
+ return -EINVAL;
+
+ return imx_rproc_attach_pd(priv);
+ }
rproc_set_feature(priv->rproc, RPROC_FEAT_ATTACH_RECOVERY);
priv->rproc->state = RPROC_DETACHED;