diff options
Diffstat (limited to 'drivers/remoteproc/imx_rproc.c')
| -rw-r--r-- | drivers/remoteproc/imx_rproc.c | 238 |
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[] = { |
