Register SCP core 1 as a subdevice of core 0 to control the boot sequence and watchdog handling. The core 1 has to boot after core 0 because the SCP clock and SRAM power is controlled by SCP core 0. When SCP core 0 reports a watchdog timeout event, the SRAM is emptied before rebooting the SCP core 0, forcing the reload of the SCP core 1 image. Signed-off-by: Tinghan Shen <tinghan.shen@xxxxxxxxxxxx> --- drivers/remoteproc/mtk_common.h | 8 ++++ drivers/remoteproc/mtk_scp.c | 71 +++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/drivers/remoteproc/mtk_common.h b/drivers/remoteproc/mtk_common.h index 54265c515315..dcde25f8bbf9 100644 --- a/drivers/remoteproc/mtk_common.h +++ b/drivers/remoteproc/mtk_common.h @@ -95,6 +95,13 @@ struct scp_ipi_desc { void *priv; }; +struct scp_subdev_core { + struct rproc_subdev subdev; + struct mtk_scp *scp; +}; + +#define to_subdev_core(d) container_of(d, struct scp_subdev_core, subdev) + struct mtk_scp; struct mtk_scp_of_data { @@ -142,6 +149,7 @@ struct mtk_scp { struct rproc_subdev *rpmsg_subdev; struct mtk_scp *main_scp; + struct rproc_subdev *core_subdev; }; /** diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index f7b738743ba9..2d43338b96da 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -871,6 +871,54 @@ static void scp_remove_rpmsg_subdev(struct mtk_scp *scp) } } +static int scp_core_subdev_start(struct rproc_subdev *subdev) +{ + struct scp_subdev_core *subdev_core = to_subdev_core(subdev); + struct mtk_scp *scp = subdev_core->scp; + + rproc_boot(scp->rproc); + + return 0; +} + +static void scp_core_subdev_stop(struct rproc_subdev *subdev, bool crashed) +{ + struct scp_subdev_core *subdev_core = to_subdev_core(subdev); + struct mtk_scp *scp = subdev_core->scp; + + rproc_shutdown(scp->rproc); +} + +static int scp_core_subdev_register(struct mtk_scp *scp) +{ + struct device *dev = scp->dev; + struct scp_subdev_core *subdev_core; + + subdev_core = devm_kzalloc(dev, sizeof(*subdev_core), GFP_KERNEL); + if (!subdev_core) { + scp->core_subdev = NULL; + return -ENOMEM; + } + + subdev_core->scp = scp; + subdev_core->subdev.start = scp_core_subdev_start; + subdev_core->subdev.stop = scp_core_subdev_stop; + + scp->core_subdev = &subdev_core->subdev; + rproc_add_subdev(scp->main_scp->rproc, scp->core_subdev); + + return 0; +} + +static void scp_core_subdev_unregister(struct mtk_scp *scp) +{ + if (scp->core_subdev) { + rproc_remove_subdev(scp->main_scp->rproc, scp->core_subdev); + devm_kfree(scp->dev, to_subdev_core(scp->core_subdev)); + scp->core_subdev = NULL; + } +} + static int scp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -974,6 +1022,23 @@ static int scp_probe(struct platform_device *pdev) goto remove_subdev; } + if (of_device_is_compatible(np, "mediatek,mt8195-scp-core")) { + ret = scp_core_subdev_register(scp); + if (ret) { + dev_err_probe(dev, ret, "Failed to register subdev\n"); + goto remove_subdev; + } + + /* sub cores are booted as subdevices of main core. */ + rproc->auto_boot = false; + } else { + ret = devm_of_platform_populate(dev); + if (ret) { + dev_err_probe(dev, ret, "Failed to probe sub cores\n"); + goto remove_subdev; + } + } + ret = rproc_add(rproc); if (ret) goto remove_subdev; @@ -981,6 +1046,7 @@ static int scp_probe(struct platform_device *pdev) return 0; remove_subdev: + scp_core_subdev_unregister(scp); scp_remove_rpmsg_subdev(scp); scp_ipi_unregister(scp, SCP_IPI_INIT); release_dev_mem: @@ -997,6 +1063,11 @@ static int scp_remove(struct platform_device *pdev) struct mtk_scp *scp = platform_get_drvdata(pdev); int i; + if (of_device_is_compatible(scp->dev->of_node, "mediatek,mt8195-scp-core")) + scp_core_subdev_unregister(scp); + else + devm_of_platform_depopulate(scp->dev); + rproc_del(scp->rproc); scp_remove_rpmsg_subdev(scp); scp_ipi_unregister(scp, SCP_IPI_INIT); -- 2.18.0