summaryrefslogtreecommitdiff
path: root/drivers/remoteproc/imx_rproc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/remoteproc/imx_rproc.c')
-rw-r--r--drivers/remoteproc/imx_rproc.c238
1 files changed, 99 insertions, 139 deletions
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index bb25221a4a89..3be8790c14a2 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -93,7 +93,7 @@ struct imx_rproc_mem {
#define ATT_CORE(I) BIT((I))
static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool tx_block);
-static void imx_rproc_free_mbox(struct rproc *rproc);
+static void imx_rproc_free_mbox(void *data);
struct imx_rproc {
struct device *dev;
@@ -490,50 +490,44 @@ static int imx_rproc_prepare(struct rproc *rproc)
{
struct imx_rproc *priv = rproc->priv;
struct device_node *np = priv->dev->of_node;
- struct of_phandle_iterator it;
struct rproc_mem_entry *mem;
- struct reserved_mem *rmem;
+ int i = 0;
u32 da;
/* Register associated reserved memory regions */
- of_phandle_iterator_init(&it, np, "memory-region", NULL, 0);
- while (of_phandle_iterator_next(&it) == 0) {
+ while (1) {
+ int err;
+ struct resource res;
+
+ err = of_reserved_mem_region_to_resource(np, i++, &res);
+ if (err)
+ return 0;
+
/*
* Ignore the first memory region which will be used vdev buffer.
* No need to do extra handlings, rproc_add_virtio_dev will handle it.
*/
- if (!strcmp(it.node->name, "vdev0buffer"))
+ if (strstarts(res.name, "vdev0buffer"))
continue;
- if (!strcmp(it.node->name, "rsc-table"))
+ if (strstarts(res.name, "rsc-table"))
continue;
- rmem = of_reserved_mem_lookup(it.node);
- if (!rmem) {
- of_node_put(it.node);
- dev_err(priv->dev, "unable to acquire memory-region\n");
- return -EINVAL;
- }
-
/* No need to translate pa to da, i.MX use same map */
- da = rmem->base;
+ da = res.start;
/* Register memory region */
- mem = rproc_mem_entry_init(priv->dev, NULL, (dma_addr_t)rmem->base, rmem->size, da,
+ mem = rproc_mem_entry_init(priv->dev, NULL, (dma_addr_t)res.start,
+ resource_size(&res), da,
imx_rproc_mem_alloc, imx_rproc_mem_release,
- it.node->name);
-
- if (mem) {
- rproc_coredump_add_segment(rproc, da, rmem->size);
- } else {
- of_node_put(it.node);
+ "%.*s", strchrnul(res.name, '@') - res.name,
+ res.name);
+ if (!mem)
return -ENOMEM;
- }
+ rproc_coredump_add_segment(rproc, da, resource_size(&res));
rproc_add_carveout(rproc, mem);
}
-
- return 0;
}
static int imx_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
@@ -575,13 +569,9 @@ static int imx_rproc_attach(struct rproc *rproc)
return imx_rproc_xtr_mbox_init(rproc, true);
}
-static int imx_rproc_detach(struct rproc *rproc)
+static int imx_rproc_scu_api_detach(struct rproc *rproc)
{
struct imx_rproc *priv = rproc->priv;
- const struct imx_rproc_dcfg *dcfg = priv->dcfg;
-
- if (dcfg->method != IMX_RPROC_SCU_API)
- return -EOPNOTSUPP;
if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id))
return -EOPNOTSUPP;
@@ -591,6 +581,17 @@ static int imx_rproc_detach(struct rproc *rproc)
return 0;
}
+static int imx_rproc_detach(struct rproc *rproc)
+{
+ struct imx_rproc *priv = rproc->priv;
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+
+ if (!dcfg->ops || !dcfg->ops->detach)
+ return -EOPNOTSUPP;
+
+ return dcfg->ops->detach(rproc);
+}
+
static struct resource_table *imx_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz)
{
struct imx_rproc *priv = rproc->priv;
@@ -664,47 +665,37 @@ static int imx_rproc_addr_init(struct imx_rproc *priv,
}
/* memory-region is optional property */
- nph = of_count_phandle_with_args(np, "memory-region", NULL);
+ nph = of_reserved_mem_region_count(np);
if (nph <= 0)
return 0;
/* remap optional addresses */
for (a = 0; a < nph; a++) {
- struct device_node *node;
struct resource res;
- node = of_parse_phandle(np, "memory-region", a);
- if (!node)
- continue;
- /* Not map vdevbuffer, vdevring region */
- if (!strncmp(node->name, "vdev", strlen("vdev"))) {
- of_node_put(node);
- continue;
- }
- err = of_address_to_resource(node, 0, &res);
+ err = of_reserved_mem_region_to_resource(np, a, &res);
if (err) {
dev_err(dev, "unable to resolve memory region\n");
- of_node_put(node);
return err;
}
- if (b >= IMX_RPROC_MEM_MAX) {
- of_node_put(node);
+ /* Not map vdevbuffer, vdevring region */
+ if (strstarts(res.name, "vdev"))
+ continue;
+
+ if (b >= IMX_RPROC_MEM_MAX)
break;
- }
/* Not use resource version, because we might share region */
- priv->mem[b].cpu_addr = devm_ioremap_wc(&pdev->dev, res.start, resource_size(&res));
+ priv->mem[b].cpu_addr = devm_ioremap_resource_wc(&pdev->dev, &res);
if (!priv->mem[b].cpu_addr) {
dev_err(dev, "failed to remap %pr\n", &res);
- of_node_put(node);
return -ENOMEM;
}
priv->mem[b].sys_addr = res.start;
priv->mem[b].size = resource_size(&res);
- if (!strcmp(node->name, "rsc-table"))
+ if (!strcmp(res.name, "rsc-table"))
priv->rsc_table = priv->mem[b].cpu_addr;
- of_node_put(node);
b++;
}
@@ -780,8 +771,9 @@ static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool tx_block)
return 0;
}
-static void imx_rproc_free_mbox(struct rproc *rproc)
+static void imx_rproc_free_mbox(void *data)
{
+ struct rproc *rproc = data;
struct imx_rproc *priv = rproc->priv;
if (priv->tx_ch) {
@@ -795,13 +787,9 @@ static void imx_rproc_free_mbox(struct rproc *rproc)
}
}
-static void imx_rproc_put_scu(struct rproc *rproc)
+static void imx_rproc_put_scu(void *data)
{
- struct imx_rproc *priv = rproc->priv;
- const struct imx_rproc_dcfg *dcfg = priv->dcfg;
-
- if (dcfg->method != IMX_RPROC_SCU_API)
- return;
+ struct imx_rproc *priv = data;
if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id)) {
dev_pm_domain_detach_list(priv->pd_list);
@@ -943,6 +931,10 @@ static int imx_rproc_scu_api_detect_mode(struct rproc *rproc)
else
priv->core_index = 0;
+ ret = devm_add_action_or_reset(dev, imx_rproc_put_scu, priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add action for put scu\n");
+
/*
* 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.
@@ -1001,35 +993,6 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv)
return dcfg->ops->detect_mode(priv->rproc);
}
-static int imx_rproc_clk_enable(struct imx_rproc *priv)
-{
- const struct imx_rproc_dcfg *dcfg = priv->dcfg;
- struct device *dev = priv->dev;
- int ret;
-
- /* Remote core is not under control of Linux or it is managed by SCU API */
- if (dcfg->method == IMX_RPROC_NONE || dcfg->method == IMX_RPROC_SCU_API)
- return 0;
-
- priv->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(priv->clk)) {
- dev_err(dev, "Failed to get clock\n");
- return PTR_ERR(priv->clk);
- }
-
- /*
- * clk for M4 block including memory. Should be
- * enabled before .start for FW transfer.
- */
- ret = clk_prepare_enable(priv->clk);
- if (ret) {
- dev_err(dev, "Failed to enable clock\n");
- return ret;
- }
-
- return 0;
-}
-
static int imx_rproc_sys_off_handler(struct sys_off_data *data)
{
struct rproc *rproc = data->cb_data;
@@ -1046,6 +1009,13 @@ static int imx_rproc_sys_off_handler(struct sys_off_data *data)
return NOTIFY_DONE;
}
+static void imx_rproc_destroy_workqueue(void *data)
+{
+ struct workqueue_struct *workqueue = data;
+
+ destroy_workqueue(workqueue);
+}
+
static int imx_rproc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1077,25 +1047,38 @@ static int imx_rproc_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ ret = devm_add_action_or_reset(dev, imx_rproc_destroy_workqueue, priv->workqueue);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add devm destroy workqueue action\n");
+
INIT_WORK(&priv->rproc_work, imx_rproc_vq_work);
ret = imx_rproc_xtr_mbox_init(rproc, true);
if (ret)
- goto err_put_wkq;
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, imx_rproc_free_mbox, rproc);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to add devm free mbox action: %d\n", ret);
ret = imx_rproc_addr_init(priv, pdev);
- if (ret) {
- dev_err(dev, "failed on imx_rproc_addr_init\n");
- goto err_put_mbox;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed on imx_rproc_addr_init\n");
ret = imx_rproc_detect_mode(priv);
if (ret)
- goto err_put_mbox;
+ return dev_err_probe(dev, ret, "failed on detect mode\n");
- ret = imx_rproc_clk_enable(priv);
- if (ret)
- goto err_put_scu;
+ /*
+ * Handle clocks when remote core is under control of Linux AND the
+ * clocks are not managed by system firmware.
+ */
+ if (dcfg->flags & IMX_RPROC_NEED_CLKS) {
+ priv->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk), "Failed to enable clock\n");
+ }
if (rproc->state != RPROC_DETACHED)
rproc->auto_boot = of_property_read_bool(np, "fsl,auto-boot");
@@ -1110,45 +1093,32 @@ static int imx_rproc_probe(struct platform_device *pdev)
ret = devm_register_sys_off_handler(dev, SYS_OFF_MODE_POWER_OFF_PREPARE,
SYS_OFF_PRIO_DEFAULT,
imx_rproc_sys_off_handler, rproc);
- if (ret) {
- dev_err(dev, "register power off handler failure\n");
- goto err_put_clk;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "register power off handler failure\n");
ret = devm_register_sys_off_handler(dev, SYS_OFF_MODE_RESTART_PREPARE,
SYS_OFF_PRIO_DEFAULT,
imx_rproc_sys_off_handler, rproc);
- if (ret) {
- dev_err(dev, "register restart handler failure\n");
- goto err_put_clk;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "register restart handler failure\n");
}
- if (dcfg->method == IMX_RPROC_SCU_API) {
- pm_runtime_enable(dev);
- ret = pm_runtime_resume_and_get(dev);
- if (ret) {
- dev_err(dev, "pm_runtime get failed: %d\n", ret);
- goto err_put_clk;
- }
- }
+ pm_runtime_enable(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "pm_runtime get failed\n");
- ret = rproc_add(rproc);
+ ret = devm_rproc_add(dev, rproc);
if (ret) {
dev_err(dev, "rproc_add failed\n");
- goto err_put_clk;
+ goto err_put_pm;
}
return 0;
-err_put_clk:
- clk_disable_unprepare(priv->clk);
-err_put_scu:
- imx_rproc_put_scu(rproc);
-err_put_mbox:
- imx_rproc_free_mbox(rproc);
-err_put_wkq:
- destroy_workqueue(priv->workqueue);
+err_put_pm:
+ pm_runtime_disable(dev);
+ pm_runtime_put_noidle(dev);
return ret;
}
@@ -1158,15 +1128,8 @@ static void imx_rproc_remove(struct platform_device *pdev)
struct rproc *rproc = platform_get_drvdata(pdev);
struct imx_rproc *priv = rproc->priv;
- if (priv->dcfg->method == IMX_RPROC_SCU_API) {
- pm_runtime_disable(priv->dev);
- pm_runtime_put(priv->dev);
- }
- clk_disable_unprepare(priv->clk);
- rproc_del(rproc);
- imx_rproc_put_scu(rproc);
- imx_rproc_free_mbox(rproc);
- destroy_workqueue(priv->workqueue);
+ pm_runtime_disable(priv->dev);
+ pm_runtime_put_noidle(priv->dev);
}
static const struct imx_rproc_plat_ops imx_rproc_ops_arm_smc = {
@@ -1184,6 +1147,7 @@ static const struct imx_rproc_plat_ops imx_rproc_ops_mmio = {
static const struct imx_rproc_plat_ops imx_rproc_ops_scu_api = {
.start = imx_rproc_scu_api_start,
.stop = imx_rproc_scu_api_stop,
+ .detach = imx_rproc_scu_api_detach,
.detect_mode = imx_rproc_scu_api_detect_mode,
};
@@ -1196,15 +1160,15 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = {
.gpr_wait = IMX8M_GPR22_CM7_CPUWAIT,
.att = imx_rproc_att_imx8mn,
.att_size = ARRAY_SIZE(imx_rproc_att_imx8mn),
- .method = IMX_RPROC_MMIO,
.ops = &imx_rproc_ops_mmio,
+ .flags = IMX_RPROC_NEED_CLKS,
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = {
.att = imx_rproc_att_imx8mn,
.att_size = ARRAY_SIZE(imx_rproc_att_imx8mn),
- .method = IMX_RPROC_SMC,
.ops = &imx_rproc_ops_arm_smc,
+ .flags = IMX_RPROC_NEED_CLKS,
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = {
@@ -1214,34 +1178,30 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = {
.src_stop = IMX7D_M4_STOP,
.att = imx_rproc_att_imx8mq,
.att_size = ARRAY_SIZE(imx_rproc_att_imx8mq),
- .method = IMX_RPROC_MMIO,
.ops = &imx_rproc_ops_mmio,
+ .flags = IMX_RPROC_NEED_CLKS,
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qm = {
.att = imx_rproc_att_imx8qm,
.att_size = ARRAY_SIZE(imx_rproc_att_imx8qm),
- .method = IMX_RPROC_SCU_API,
.ops = &imx_rproc_ops_scu_api,
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qxp = {
.att = imx_rproc_att_imx8qxp,
.att_size = ARRAY_SIZE(imx_rproc_att_imx8qxp),
- .method = IMX_RPROC_SCU_API,
.ops = &imx_rproc_ops_scu_api,
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx8ulp = {
.att = imx_rproc_att_imx8ulp,
.att_size = ARRAY_SIZE(imx_rproc_att_imx8ulp),
- .method = IMX_RPROC_NONE,
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx7ulp = {
.att = imx_rproc_att_imx7ulp,
.att_size = ARRAY_SIZE(imx_rproc_att_imx7ulp),
- .method = IMX_RPROC_NONE,
.flags = IMX_RPROC_NEED_SYSTEM_OFF,
};
@@ -1252,8 +1212,8 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = {
.src_stop = IMX7D_M4_STOP,
.att = imx_rproc_att_imx7d,
.att_size = ARRAY_SIZE(imx_rproc_att_imx7d),
- .method = IMX_RPROC_MMIO,
.ops = &imx_rproc_ops_mmio,
+ .flags = IMX_RPROC_NEED_CLKS,
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = {
@@ -1263,15 +1223,15 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = {
.src_stop = IMX6SX_M4_STOP,
.att = imx_rproc_att_imx6sx,
.att_size = ARRAY_SIZE(imx_rproc_att_imx6sx),
- .method = IMX_RPROC_MMIO,
.ops = &imx_rproc_ops_mmio,
+ .flags = IMX_RPROC_NEED_CLKS,
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = {
.att = imx_rproc_att_imx93,
.att_size = ARRAY_SIZE(imx_rproc_att_imx93),
- .method = IMX_RPROC_SMC,
.ops = &imx_rproc_ops_arm_smc,
+ .flags = IMX_RPROC_NEED_CLKS,
};
static const struct of_device_id imx_rproc_of_match[] = {