diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/remoteproc/Kconfig | 1 | ||||
-rw-r--r-- | drivers/remoteproc/imx_rproc.c | 209 | ||||
-rw-r--r-- | drivers/remoteproc/pru_rproc.c | 3 | ||||
-rw-r--r-- | drivers/remoteproc/qcom_q6v5.c | 2 | ||||
-rw-r--r-- | drivers/remoteproc/qcom_q6v5_pas.c | 22 | ||||
-rw-r--r-- | drivers/remoteproc/qcom_wcnss.c | 5 | ||||
-rw-r--r-- | drivers/remoteproc/remoteproc_cdev.c | 2 | ||||
-rw-r--r-- | drivers/remoteproc/remoteproc_core.c | 72 | ||||
-rw-r--r-- | drivers/remoteproc/remoteproc_elf_loader.c | 12 | ||||
-rw-r--r-- | drivers/remoteproc/remoteproc_virtio.c | 6 | ||||
-rw-r--r-- | drivers/remoteproc/stm32_rproc.c | 16 | ||||
-rw-r--r-- | drivers/remoteproc/ti_k3_r5_remoteproc.c | 151 | ||||
-rw-r--r-- | drivers/soc/qcom/smem_state.c | 36 |
13 files changed, 431 insertions, 106 deletions
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index e68fcedc999c..9a6eedc3994a 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -26,6 +26,7 @@ config REMOTEPROC_CDEV config IMX_REMOTEPROC tristate "i.MX remoteproc support" depends on ARCH_MXC + depends on HAVE_ARM_SMCCC select MAILBOX help Say y here to support iMX's remote processors via the remote diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index d6338872c6db..d88f76f5305e 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -3,6 +3,7 @@ * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> */ +#include <linux/arm-smccc.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/interrupt.h> @@ -50,6 +51,11 @@ #define IMX_RPROC_MEM_MAX 32 +#define IMX_SIP_RPROC 0xC2000005 +#define IMX_SIP_RPROC_START 0x00 +#define IMX_SIP_RPROC_STARTED 0x01 +#define IMX_SIP_RPROC_STOP 0x02 + /** * struct imx_rproc_mem - slim internal memory structure * @cpu_addr: MPU virtual address of the memory region @@ -74,6 +80,15 @@ struct imx_rproc_att { int flags; }; +/* Remote core start/stop method */ +enum imx_rproc_method { + IMX_RPROC_NONE, + /* Through syscon regmap */ + IMX_RPROC_MMIO, + /* Through ARM SMCCC */ + IMX_RPROC_SMC, +}; + struct imx_rproc_dcfg { u32 src_reg; u32 src_mask; @@ -81,6 +96,7 @@ struct imx_rproc_dcfg { u32 src_stop; const struct imx_rproc_att *att; size_t att_size; + enum imx_rproc_method method; }; struct imx_rproc { @@ -98,6 +114,36 @@ struct imx_rproc { void __iomem *rsc_table; }; +static const struct imx_rproc_att imx_rproc_att_imx8mn[] = { + /* dev addr , sys addr , size , flags */ + /* ITCM */ + { 0x00000000, 0x007E0000, 0x00020000, ATT_OWN }, + /* OCRAM_S */ + { 0x00180000, 0x00180000, 0x00009000, 0 }, + /* OCRAM */ + { 0x00900000, 0x00900000, 0x00020000, 0 }, + /* OCRAM */ + { 0x00920000, 0x00920000, 0x00020000, 0 }, + /* OCRAM */ + { 0x00940000, 0x00940000, 0x00050000, 0 }, + /* QSPI Code - alias */ + { 0x08000000, 0x08000000, 0x08000000, 0 }, + /* DDR (Code) - alias */ + { 0x10000000, 0x40000000, 0x0FFE0000, 0 }, + /* DTCM */ + { 0x20000000, 0x00800000, 0x00020000, ATT_OWN }, + /* OCRAM_S - alias */ + { 0x20180000, 0x00180000, 0x00008000, ATT_OWN }, + /* OCRAM */ + { 0x20200000, 0x00900000, 0x00020000, ATT_OWN }, + /* OCRAM */ + { 0x20220000, 0x00920000, 0x00020000, ATT_OWN }, + /* OCRAM */ + { 0x20240000, 0x00940000, 0x00040000, ATT_OWN }, + /* DDR (Data) */ + { 0x40000000, 0x40000000, 0x80000000, 0 }, +}; + static const struct imx_rproc_att imx_rproc_att_imx8mq[] = { /* dev addr , sys addr , size , flags */ /* TCML - alias */ @@ -126,6 +172,20 @@ static const struct imx_rproc_att imx_rproc_att_imx8mq[] = { { 0x40000000, 0x40000000, 0x80000000, 0 }, }; +static const struct imx_rproc_att imx_rproc_att_imx8ulp[] = { + {0x1FFC0000, 0x1FFC0000, 0xC0000, ATT_OWN}, + {0x21000000, 0x21000000, 0x10000, ATT_OWN}, + {0x80000000, 0x80000000, 0x60000000, 0} +}; + +static const struct imx_rproc_att imx_rproc_att_imx7ulp[] = { + {0x1FFD0000, 0x1FFD0000, 0x30000, ATT_OWN}, + {0x20000000, 0x20000000, 0x10000, ATT_OWN}, + {0x2F000000, 0x2F000000, 0x20000, ATT_OWN}, + {0x2F020000, 0x2F020000, 0x20000, ATT_OWN}, + {0x60000000, 0x60000000, 0x40000000, 0} +}; + static const struct imx_rproc_att imx_rproc_att_imx7d[] = { /* dev addr , sys addr , size , flags */ /* OCRAM_S (M4 Boot code) - alias */ @@ -176,6 +236,12 @@ static const struct imx_rproc_att imx_rproc_att_imx6sx[] = { { 0x80000000, 0x80000000, 0x60000000, 0 }, }; +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, +}; + static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = { .src_reg = IMX7D_SRC_SCR, .src_mask = IMX7D_M4_RST_MASK, @@ -183,6 +249,19 @@ 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, +}; + +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, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { @@ -192,6 +271,7 @@ 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, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { @@ -201,6 +281,7 @@ 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, }; static int imx_rproc_start(struct rproc *rproc) @@ -208,12 +289,24 @@ static int imx_rproc_start(struct rproc *rproc) struct imx_rproc *priv = rproc->priv; const struct imx_rproc_dcfg *dcfg = priv->dcfg; struct device *dev = priv->dev; + struct arm_smccc_res res; int ret; - ret = regmap_update_bits(priv->regmap, dcfg->src_reg, - dcfg->src_mask, dcfg->src_start); + switch (dcfg->method) { + case IMX_RPROC_MMIO: + ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, + dcfg->src_start); + break; + case IMX_RPROC_SMC: + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res); + ret = res.a0; + break; + default: + return -EOPNOTSUPP; + } + if (ret) - dev_err(dev, "Failed to enable M4!\n"); + dev_err(dev, "Failed to enable remote core!\n"); return ret; } @@ -223,12 +316,26 @@ static int imx_rproc_stop(struct rproc *rproc) struct imx_rproc *priv = rproc->priv; const struct imx_rproc_dcfg *dcfg = priv->dcfg; struct device *dev = priv->dev; + struct arm_smccc_res res; int ret; - ret = regmap_update_bits(priv->regmap, dcfg->src_reg, - dcfg->src_mask, dcfg->src_stop); + switch (dcfg->method) { + case IMX_RPROC_MMIO: + ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, + dcfg->src_stop); + break; + case IMX_RPROC_SMC: + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STOP, 0, 0, 0, 0, 0, 0, &res); + ret = res.a0; + if (res.a1) + dev_info(dev, "Not in wfi, force stopped\n"); + break; + default: + return -EOPNOTSUPP; + } + if (ret) - dev_err(dev, "Failed to stop M4!\n"); + dev_err(dev, "Failed to stop remote core\n"); return ret; } @@ -560,12 +667,37 @@ static void imx_rproc_free_mbox(struct rproc *rproc) static int imx_rproc_detect_mode(struct imx_rproc *priv) { + struct regmap_config config = { .name = "imx-rproc" }; const struct imx_rproc_dcfg *dcfg = priv->dcfg; struct device *dev = priv->dev; + struct regmap *regmap; + struct arm_smccc_res res; int ret; u32 val; - ret = regmap_read(priv->regmap, dcfg->src_reg, &val); + switch (dcfg->method) { + case IMX_RPROC_NONE: + priv->rproc->state = RPROC_DETACHED; + return 0; + case IMX_RPROC_SMC: + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STARTED, 0, 0, 0, 0, 0, 0, &res); + if (res.a0) + priv->rproc->state = RPROC_DETACHED; + return 0; + default: + break; + } + + regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); + if (IS_ERR(regmap)) { + dev_err(dev, "failed to find syscon\n"); + return PTR_ERR(regmap); + } + + priv->regmap = regmap; + regmap_attach_dev(dev, regmap, &config); + + ret = regmap_read(regmap, dcfg->src_reg, &val); if (ret) { dev_err(dev, "Failed to read src\n"); return ret; @@ -577,24 +709,44 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv) return 0; } +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 */ + if (dcfg->method == IMX_RPROC_NONE) + 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_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct imx_rproc *priv; struct rproc *rproc; - struct regmap_config config = { .name = "imx-rproc" }; const struct imx_rproc_dcfg *dcfg; - struct regmap *regmap; int ret; - regmap = syscon_regmap_lookup_by_phandle(np, "syscon"); - if (IS_ERR(regmap)) { - dev_err(dev, "failed to find syscon\n"); - return PTR_ERR(regmap); - } - regmap_attach_dev(dev, regmap, &config); - /* set some other name then imx */ rproc = rproc_alloc(dev, "imx-rproc", &imx_rproc_ops, NULL, sizeof(*priv)); @@ -609,7 +761,6 @@ static int imx_rproc_probe(struct platform_device *pdev) priv = rproc->priv; priv->rproc = rproc; - priv->regmap = regmap; priv->dcfg = dcfg; priv->dev = dev; @@ -635,25 +786,15 @@ static int imx_rproc_probe(struct platform_device *pdev) if (ret) goto err_put_mbox; - priv->clk = devm_clk_get(dev, NULL); - if (IS_ERR(priv->clk)) { - dev_err(dev, "Failed to get clock\n"); - ret = PTR_ERR(priv->clk); - goto err_put_mbox; - } - - /* - * clk for M4 block including memory. Should be - * enabled before .start for FW transfer. - */ - ret = clk_prepare_enable(priv->clk); - if (ret) { - dev_err(&rproc->dev, "Failed to enable clock\n"); + ret = imx_rproc_clk_enable(priv); + if (ret) goto err_put_mbox; - } INIT_WORK(&priv->rproc_work, imx_rproc_vq_work); + if (rproc->state != RPROC_DETACHED) + rproc->auto_boot = of_property_read_bool(np, "fsl,auto-boot"); + ret = rproc_add(rproc); if (ret) { dev_err(dev, "rproc_add failed\n"); @@ -688,10 +829,14 @@ static int imx_rproc_remove(struct platform_device *pdev) } static const struct of_device_id imx_rproc_of_match[] = { + { .compatible = "fsl,imx7ulp-cm4", .data = &imx_rproc_cfg_imx7ulp }, { .compatible = "fsl,imx7d-cm4", .data = &imx_rproc_cfg_imx7d }, { .compatible = "fsl,imx6sx-cm4", .data = &imx_rproc_cfg_imx6sx }, { .compatible = "fsl,imx8mq-cm4", .data = &imx_rproc_cfg_imx8mq }, { .compatible = "fsl,imx8mm-cm4", .data = &imx_rproc_cfg_imx8mq }, + { .compatible = "fsl,imx8mn-cm7", .data = &imx_rproc_cfg_imx8mn }, + { .compatible = "fsl,imx8mp-cm7", .data = &imx_rproc_cfg_imx8mn }, + { .compatible = "fsl,imx8ulp-cm33", .data = &imx_rproc_cfg_imx8ulp }, {}, }; MODULE_DEVICE_TABLE(of, imx_rproc_of_match); diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index e5778e476245..1777a01fa84e 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -887,6 +887,9 @@ static const struct of_device_id pru_rproc_match[] = { { .compatible = "ti,am3356-pru", .data = &pru_data }, { .compatible = "ti,am4376-pru", .data = &pru_data }, { .compatible = "ti,am5728-pru", .data = &pru_data }, + { .compatible = "ti,am642-pru", .data = &k3_pru_data }, + { .compatible = "ti,am642-rtu", .data = &k3_rtu_data }, + { .compatible = "ti,am642-tx-pru", .data = &k3_tx_pru_data }, { .compatible = "ti,k2g-pru", .data = &pru_data }, { .compatible = "ti,am654-pru", .data = &k3_pru_data }, { .compatible = "ti,am654-rtu", .data = &k3_rtu_data }, diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c index 9627a950928e..7e9244c748da 100644 --- a/drivers/remoteproc/qcom_q6v5.c +++ b/drivers/remoteproc/qcom_q6v5.c @@ -280,7 +280,7 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev, return ret; } - q6v5->state = qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit); + q6v5->state = devm_qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit); if (IS_ERR(q6v5->state)) { dev_err(&pdev->dev, "failed to acquire stop state\n"); return PTR_ERR(q6v5->state); diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index b921fc26cd04..a79bee901e9b 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -689,6 +689,25 @@ static const struct adsp_data mpss_resource_init = { .ssctl_id = 0x12, }; +static const struct adsp_data sc8180x_mpss_resource = { + .crash_reason_smem = 421, + .firmware_name = "modem.mdt", + .pas_id = 4, + .has_aggre2_clk = false, + .auto_boot = false, + .active_pd_names = (char*[]){ + "load_state", + NULL + }, + .proxy_pd_names = (char*[]){ + "cx", + NULL + }, + .ssr_name = "mpss", + .sysmon_name = "modem", + .ssctl_id = 0x12, +}; + static const struct adsp_data slpi_resource_init = { .crash_reason_smem = 424, .firmware_name = "slpi.mdt", @@ -811,6 +830,9 @@ static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,qcs404-cdsp-pas", .data = &cdsp_resource_init }, { .compatible = "qcom,qcs404-wcss-pas", .data = &wcss_resource_init }, { .compatible = "qcom,sc7180-mpss-pas", .data = &mpss_resource_init}, + { .compatible = "qcom,sc8180x-adsp-pas", .data = &sm8150_adsp_resource}, + { .compatible = "qcom,sc8180x-cdsp-pas", .data = &sm8150_cdsp_resource}, + { .compatible = "qcom,sc8180x-mpss-pas", .data = &sc8180x_mpss_resource}, { .compatible = "qcom,sdm845-adsp-pas", .data = &adsp_resource_init}, { .compatible = "qcom,sdm845-cdsp-pas", .data = &cdsp_resource_init}, { .compatible = "qcom,sdx55-mpss-pas", .data = &sdx55_mpss_resource}, diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index 5f3455aa7e0e..f1cbc6b2edbb 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -624,8 +624,8 @@ static int wcnss_probe(struct platform_device *pdev) wcnss->stop_ack_irq = ret; if (wcnss->stop_ack_irq) { - wcnss->state = qcom_smem_state_get(&pdev->dev, "stop", - &wcnss->stop_bit); + wcnss->state = devm_qcom_smem_state_get(&pdev->dev, "stop", + &wcnss->stop_bit); if (IS_ERR(wcnss->state)) { ret = PTR_ERR(wcnss->state); goto detach_pds; @@ -659,7 +659,6 @@ static int wcnss_remove(struct platform_device *pdev) of_platform_depopulate(&pdev->dev); - qcom_smem_state_put(wcnss->state); rproc_del(wcnss->rproc); qcom_remove_sysmon_subdev(wcnss->sysmon); diff --git a/drivers/remoteproc/remoteproc_cdev.c b/drivers/remoteproc/remoteproc_cdev.c index 0b8a84c04f76..4ad98b0b8caa 100644 --- a/drivers/remoteproc/remoteproc_cdev.c +++ b/drivers/remoteproc/remoteproc_cdev.c @@ -124,7 +124,7 @@ int rproc_char_device_add(struct rproc *rproc) void rproc_char_device_remove(struct rproc *rproc) { - __unregister_chrdev(MAJOR(rproc->dev.devt), rproc->index, 1, "remoteproc"); + cdev_del(&rproc->cdev); } void __init rproc_init_cdev(void) diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 39cf44cb0803..7de5905d276a 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -166,6 +166,7 @@ EXPORT_SYMBOL(rproc_va_to_pa); * @rproc: handle of a remote processor * @da: remoteproc device address to translate * @len: length of the memory region @da is pointing to + * @is_iomem: optional pointer filled in to indicate if @da is iomapped memory * * Some remote processors will ask us to allocate them physically contiguous * memory regions (which we call "carveouts"), and map them to specific @@ -183,12 +184,12 @@ EXPORT_SYMBOL(rproc_va_to_pa); * translations on the internal remoteproc memory regions through a platform * implementation specific da_to_va ops, if present. * - * The function returns a valid kernel address on success or NULL on failure. - * * Note: phys_to_virt(iommu_iova_to_phys(rproc->domain, da)) will work too, * but only on kernel direct mapped RAM memory. Instead, we're just using * here the output of the DMA API for the carveouts, which should be more * correct. + * + * Return: a valid kernel address on success or NULL on failure */ void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { @@ -509,7 +510,7 @@ static int copy_dma_range_map(struct device *to, struct device *from) * use RSC_DEVMEM resource entries to map their required @da to the physical * address of their base CMA region (ouch, hacky!). * - * Returns 0 on success, or an appropriate error code otherwise + * Return: 0 on success, or an appropriate error code otherwise */ static int rproc_handle_vdev(struct rproc *rproc, void *ptr, int offset, int avail) @@ -644,7 +645,7 @@ void rproc_vdev_release(struct kref *ref) * support dynamically allocating this address using the generic * DMA API (but currently there isn't a use case for that). * - * Returns 0 on success, or an appropriate error code otherwise + * Return: 0 on success, or an appropriate error code otherwise */ static int rproc_handle_trace(struct rproc *rproc, void *ptr, int offset, int avail) @@ -721,6 +722,8 @@ static int rproc_handle_trace(struct rproc *rproc, void *ptr, * tell us ranges of physical addresses the firmware is allowed to request, * and not allow firmwares to request access to physical addresses that * are outside those ranges. + * + * Return: 0 on success, or an appropriate error code otherwise */ static int rproc_handle_devmem(struct rproc *rproc, void *ptr, int offset, int avail) @@ -783,6 +786,8 @@ out: * * This function allocate specified memory entry @mem using * dma_alloc_coherent() as default allocator + * + * Return: 0 on success, or an appropriate error code otherwise */ static int rproc_alloc_carveout(struct rproc *rproc, struct rproc_mem_entry *mem) @@ -889,6 +894,8 @@ dma_free: * * This function releases specified memory entry @mem allocated via * rproc_alloc_carveout() function by @rproc. + * + * Return: 0 on success, or an appropriate error code otherwise */ static int rproc_release_carveout(struct rproc *rproc, struct rproc_mem_entry *mem) @@ -918,6 +925,8 @@ static int rproc_release_carveout(struct rproc *rproc, * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB * pressure is important; it may have a substantial impact on performance. + * + * Return: 0 on success, or an appropriate error code otherwise */ static int rproc_handle_carveout(struct rproc *rproc, void *ptr, int offset, int avail) @@ -1006,6 +1015,8 @@ EXPORT_SYMBOL(rproc_add_carveout); * * This function allocates a rproc_mem_entry struct and fill it with parameters * provided by client. + * + * Return: a valid pointer on success, or NULL on failure */ __printf(8, 9) struct rproc_mem_entry * @@ -1050,6 +1061,8 @@ EXPORT_SYMBOL(rproc_mem_entry_init); * * This function allocates a rproc_mem_entry struct and fill it with parameters * provided by client. + * + * Return: a valid pointer on success, or NULL on failure */ __printf(5, 6) struct rproc_mem_entry * @@ -1881,6 +1894,8 @@ static int __rproc_detach(struct rproc *rproc) * remoteproc functional again. * * This function can sleep, so it cannot be called from atomic context. + * + * Return: 0 on success or a negative value upon failure */ int rproc_trigger_recovery(struct rproc *rproc) { @@ -1965,7 +1980,7 @@ static void rproc_crash_handler_work(struct work_struct *work) * If the remote processor is already powered on, this function immediately * returns (successfully). * - * Returns 0 on success, and an appropriate error value otherwise. + * Return: 0 on success, and an appropriate error value otherwise */ int rproc_boot(struct rproc *rproc) { @@ -2100,6 +2115,8 @@ EXPORT_SYMBOL(rproc_shutdown); * no longer available. From there it should be possible to remove the * platform driver and even power cycle the application processor (if the HW * supports it) without needing to switch off the remote processor. + * + * Return: 0 on success, and an appropriate error value otherwise */ int rproc_detach(struct rproc *rproc) { @@ -2152,7 +2169,7 @@ EXPORT_SYMBOL(rproc_detach); * This function increments the remote processor's refcount, so always * use rproc_put() to decrement it back once rproc isn't needed anymore. * - * Returns the rproc handle on success, and NULL on failure. + * Return: rproc handle on success, and NULL on failure */ #ifdef CONFIG_OF struct rproc *rproc_get_by_phandle(phandle phandle) @@ -2302,8 +2319,6 @@ static int rproc_validate(struct rproc *rproc) * This is called by the platform-specific rproc implementation, whenever * a new remote processor device is probed. * - * Returns 0 on success and an appropriate error code otherwise. - * * Note: this function initiates an asynchronous firmware loading * context, which will look for virtio devices supported by the rproc's * firmware. @@ -2311,35 +2326,39 @@ static int rproc_validate(struct rproc *rproc) * If found, those virtio devices will be created and added, so as a result * of registering this remote processor, additional virtio drivers might be * probed. + * + * Return: 0 on success and an appropriate error code otherwise */ int rproc_add(struct rproc *rproc) { struct device *dev = &rproc->dev; int ret; - ret = device_add(dev); + ret = rproc_validate(rproc); if (ret < 0) return ret; - ret = rproc_validate(rproc); + /* add char device for this remoteproc */ + ret = rproc_char_device_add(rproc); if (ret < 0) return ret; + ret = device_add(dev); + if (ret < 0) { + put_device(dev); + goto rproc_remove_cdev; + } + dev_info(dev, "%s is available\n", rproc->name); /* create debugfs entries */ rproc_create_debug_dir(rproc); - /* add char device for this remoteproc */ - ret = rproc_char_device_add(rproc); - if (ret < 0) - return ret; - /* if rproc is marked always-on, request it to boot */ if (rproc->auto_boot) { ret = rproc_trigger_auto_boot(rproc); if (ret < 0) - return ret; + goto rproc_remove_dev; } /* expose to rproc_get_by_phandle users */ @@ -2348,6 +2367,13 @@ int rproc_add(struct rproc *rproc) mutex_unlock(&rproc_list_mutex); return 0; + +rproc_remove_dev: + rproc_delete_debug_dir(rproc); + device_del(dev); +rproc_remove_cdev: + rproc_char_device_remove(rproc); + return ret; } EXPORT_SYMBOL(rproc_add); @@ -2364,7 +2390,7 @@ static void devm_rproc_remove(void *rproc) * This function performs like rproc_add() but the registered rproc device will * automatically be removed on driver detach. * - * Returns: 0 on success, negative errno on failure + * Return: 0 on success, negative errno on failure */ int devm_rproc_add(struct device *dev, struct rproc *rproc) { @@ -2472,10 +2498,10 @@ static int rproc_alloc_ops(struct rproc *rproc, const struct rproc_ops *ops) * implementations should then call rproc_add() to complete * the registration of the remote processor. * - * On success the new rproc is returned, and on failure, NULL. - * * Note: _never_ directly deallocate @rproc, even if it was not registered * yet. Instead, when you need to unroll rproc_alloc(), use rproc_free(). + * + * Return: new rproc pointer on success, and NULL on failure */ struct rproc *rproc_alloc(struct device *dev, const char *name, const struct rproc_ops *ops, @@ -2588,7 +2614,7 @@ EXPORT_SYMBOL(rproc_put); * of the outstanding reference created by rproc_alloc. To decrement that * one last refcount, one still needs to call rproc_free(). * - * Returns 0 on success and -EINVAL if @rproc isn't valid. + * Return: 0 on success and -EINVAL if @rproc isn't valid */ int rproc_del(struct rproc *rproc) { @@ -2603,7 +2629,6 @@ int rproc_del(struct rproc *rproc) mutex_unlock(&rproc->lock); rproc_delete_debug_dir(rproc); - rproc_char_device_remove(rproc); /* the rproc is downref'ed as soon as it's removed from the klist */ mutex_lock(&rproc_list_mutex); @@ -2614,6 +2639,7 @@ int rproc_del(struct rproc *rproc) synchronize_rcu(); device_del(&rproc->dev); + rproc_char_device_remove(rproc); return 0; } @@ -2635,7 +2661,7 @@ static void devm_rproc_free(struct device *dev, void *res) * This function performs like rproc_alloc() but the acquired rproc device will * automatically be released on driver detach. * - * Returns: new rproc instance, or NULL on failure + * Return: new rproc instance, or NULL on failure */ struct rproc *devm_rproc_alloc(struct device *dev, const char *name, const struct rproc_ops *ops, @@ -2687,7 +2713,7 @@ EXPORT_SYMBOL(rproc_remove_subdev); * rproc_get_by_child() - acquire rproc handle of @dev's ancestor * @dev: child device to find ancestor of * - * Returns the ancestor rproc instance, or NULL if not found. + * Return: the ancestor rproc instance, or NULL if not found */ struct rproc *rproc_get_by_child(struct device *dev) { diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c index 11423588965a..469c52e62faf 100644 --- a/drivers/remoteproc/remoteproc_elf_loader.c +++ b/drivers/remoteproc/remoteproc_elf_loader.c @@ -31,6 +31,8 @@ * @fw: the ELF firmware image * * Make sure this fw image is sane (ie a correct ELF32/ELF64 file). + * + * Return: 0 on success and -EINVAL upon any failure */ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw) { @@ -117,11 +119,11 @@ EXPORT_SYMBOL(rproc_elf_sanity_check); * @rproc: the remote processor handle * @fw: the ELF firmware image * - * This function returns the entry point address of the ELF - * image. - * * Note that the boot address is not a configurable property of all remote * processors. Some will always boot at a specific hard-coded address. + * + * Return: entry point address of the ELF image + * */ u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw) { @@ -152,6 +154,8 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr); * might be different: they might not have iommus, and would prefer to * directly allocate memory for every segment/resource. This is not yet * supported, though. + * + * Return: 0 on success and an appropriate error code otherwise */ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) { @@ -362,7 +366,7 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table); * This function finds the location of the loaded resource table. Don't * call this function if the table wasn't loaded yet - it's a bug if you do. * - * Returns the pointer to the resource table if it is found or NULL otherwise. + * Return: pointer to the resource table if it is found or NULL otherwise. * If the table wasn't loaded yet the result is unspecified. */ struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc, diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index 0cc617f76068..cf4d54e98e6a 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -45,7 +45,7 @@ static bool rproc_virtio_notify(struct virtqueue *vq) * when the remote processor signals that a specific virtqueue has pending * messages available. * - * Returns IRQ_NONE if no message was found in the @notifyid virtqueue, + * Return: IRQ_NONE if no message was found in the @notifyid virtqueue, * and otherwise returns IRQ_HANDLED. */ irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid) @@ -325,7 +325,7 @@ static void rproc_virtio_dev_release(struct device *dev) * This function registers a virtio device. This vdev's partent is * the rproc device. * - * Returns 0 on success or an appropriate error value otherwise. + * Return: 0 on success or an appropriate error value otherwise */ int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id) { @@ -432,6 +432,8 @@ out: * @data: must be null * * This function unregisters an existing virtio device. + * + * Return: 0 */ int rproc_remove_virtio_dev(struct device *dev, void *data) { diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c index 7353f9e7e7af..b643efcf995a 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c @@ -474,14 +474,12 @@ static int stm32_rproc_attach(struct rproc *rproc) static int stm32_rproc_detach(struct rproc *rproc) { struct stm32_rproc *ddata = rproc->priv; - int err, dummy_data, idx; + int err, idx; /* Inform the remote processor of the detach */ idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_DETACH); if (idx >= 0 && ddata->mb[idx].chan) { - /* A dummy data is sent to allow to block on transmit */ - err = mbox_send_message(ddata->mb[idx].chan, - &dummy_data); + err = mbox_send_message(ddata->mb[idx].chan, "stop"); if (err < 0) dev_warn(&rproc->dev, "warning: remote FW detach without ack\n"); } @@ -493,15 +491,13 @@ static int stm32_rproc_detach(struct rproc *rproc) static int stm32_rproc_stop(struct rproc *rproc) { struct stm32_rproc *ddata = rproc->priv; - int err, dummy_data, idx; + int err, idx; /* request shutdown of the remote processor */ if (rproc->state != RPROC_OFFLINE) { idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_SHUTDOWN); if (idx >= 0 && ddata->mb[idx].chan) { - /* a dummy data is sent to allow to block on transmit */ - err = mbox_send_message(ddata->mb[idx].chan, - &dummy_data); + err = mbox_send_message(ddata->mb[idx].chan, "detach"); if (err < 0) dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n"); } @@ -556,7 +552,7 @@ static void stm32_rproc_kick(struct rproc *rproc, int vqid) continue; if (!ddata->mb[i].chan) return; - err = mbox_send_message(ddata->mb[i].chan, (void *)(long)vqid); + err = mbox_send_message(ddata->mb[i].chan, "kick"); if (err < 0) dev_err(&rproc->dev, "%s: failed (%s, err:%d)\n", __func__, ddata->mb[i].name, err); @@ -580,7 +576,7 @@ static int stm32_rproc_da_to_pa(struct rproc *rproc, continue; *pa = da - p_mem->dev_addr + p_mem->bus_addr; - dev_dbg(dev, "da %llx to pa %#x\n", da, *pa); + dev_dbg(dev, "da %llx to pa %pap\n", da, pa); return 0; } diff --git a/drivers/remoteproc/ti_k3_r5_remoteproc.c b/drivers/remoteproc/ti_k3_r5_remoteproc.c index 5cf8d030a1f0..71615210df3e 100644 --- a/drivers/remoteproc/ti_k3_r5_remoteproc.c +++ b/drivers/remoteproc/ti_k3_r5_remoteproc.c @@ -40,6 +40,8 @@ #define PROC_BOOT_CFG_FLAG_R5_ATCM_EN 0x00002000 /* Available from J7200 SoCs onwards */ #define PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS 0x00004000 +/* Applicable to only AM64x SoCs */ +#define PROC_BOOT_CFG_FLAG_R5_SINGLE_CORE 0x00008000 /* R5 TI-SCI Processor Control Flags */ #define PROC_BOOT_CTRL_FLAG_R5_CORE_HALT 0x00000001 @@ -49,6 +51,8 @@ #define PROC_BOOT_STATUS_FLAG_R5_WFI 0x00000002 #define PROC_BOOT_STATUS_FLAG_R5_CLK_GATED 0x00000004 #define PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED 0x00000100 +/* Applicable to only AM64x SoCs */ +#define PROC_BOOT_STATUS_FLAG_R5_SINGLECORE_ONLY 0x00000200 /** * struct k3_r5_mem - internal memory structure @@ -64,19 +68,29 @@ struct k3_r5_mem { size_t size; }; +/* + * All cluster mode values are not applicable on all SoCs. The following + * are the modes supported on various SoCs: + * Split mode : AM65x, J721E, J7200 and AM64x SoCs + * LockStep mode : AM65x, J721E and J7200 SoCs + * Single-CPU mode : AM64x SoCs only + */ enum cluster_mode { CLUSTER_MODE_SPLIT = 0, CLUSTER_MODE_LOCKSTEP, + CLUSTER_MODE_SINGLECPU, }; /** * struct k3_r5_soc_data - match data to handle SoC variations * @tcm_is_double: flag to denote the larger unified TCMs in certain modes * @tcm_ecc_autoinit: flag to denote the auto-initialization of TCMs for ECC + * @single_cpu_mode: flag to denote if SoC/IP supports Single-CPU mode */ struct k3_r5_soc_data { bool tcm_is_double; bool tcm_ecc_autoinit; + bool single_cpu_mode; }; /** @@ -369,6 +383,13 @@ static inline int k3_r5_core_run(struct k3_r5_core *core) * applicable cores to allow loading into the TCMs. The .prepare() ops is * invoked by remoteproc core before any firmware loading, and is followed * by the .start() ops after loading to actually let the R5 cores run. + * + * The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to + * execute code, but combines the TCMs from both cores. The resets for both + * cores need to be released to make this possible, as the TCMs are in general + * private to each core. Only Core0 needs to be unhalted for running the + * cluster in this mode. The function uses the same reset logic as LockStep + * mode for this (though the behavior is agnostic of the reset release order). */ static int k3_r5_rproc_prepare(struct rproc *rproc) { @@ -386,7 +407,9 @@ static int k3_r5_rproc_prepare(struct rproc *rproc) return ret; mem_init_dis = !!(cfg & PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS); - ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP) ? + /* Re-use LockStep-mode reset logic for Single-CPU mode */ + ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP || + cluster->mode == CLUSTER_MODE_SINGLECPU) ? k3_r5_lockstep_release(cluster) : k3_r5_split_release(core); if (ret) { dev_err(dev, "unable to enable cores for TCM loading, ret = %d\n", @@ -427,6 +450,12 @@ static int k3_r5_rproc_prepare(struct rproc *rproc) * cores. The cores themselves are only halted in the .stop() ops, and the * .unprepare() ops is invoked by the remoteproc core after the remoteproc is * stopped. + * + * The Single-CPU mode on applicable SoCs (eg: AM64x) combines the TCMs from + * both cores. The access is made possible only with releasing the resets for + * both cores, but with only Core0 unhalted. This function re-uses the same + * reset assert logic as LockStep mode for this mode (though the behavior is + * agnostic of the reset assert order). */ static int k3_r5_rproc_unprepare(struct rproc *rproc) { @@ -436,7 +465,9 @@ static int k3_r5_rproc_unprepare(struct rproc *rproc) struct device *dev = kproc->dev; int ret; - ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP) ? + /* Re-use LockStep-mode reset logic for Single-CPU mode */ + ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP || + cluster->mode == CLUSTER_MODE_SINGLECPU) ? k3_r5_lockstep_reset(cluster) : k3_r5_split_reset(core); if (ret) dev_err(dev, "unable to disable cores, ret = %d\n", ret); @@ -455,6 +486,10 @@ static int k3_r5_rproc_unprepare(struct rproc *rproc) * first followed by Core0. The Split-mode requires that Core0 to be maintained * always in a higher power state that Core1 (implying Core1 needs to be started * always only after Core0 is started). + * + * The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to execute + * code, so only Core0 needs to be unhalted. The function uses the same logic + * flow as Split-mode for this. */ static int k3_r5_rproc_start(struct rproc *rproc) { @@ -539,6 +574,10 @@ put_mbox: * Core0 to be maintained always in a higher power state that Core1 (implying * Core1 needs to be stopped first before Core0). * + * The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to execute + * code, so only Core0 needs to be halted. The function uses the same logic + * flow as Split-mode for this. + * * Note that the R5F halt operation in general is not effective when the R5F * core is running, but is needed to make sure the core won't run after * deasserting the reset the subsequent time. The asserting of reset can @@ -665,7 +704,9 @@ static const struct rproc_ops k3_r5_rproc_ops = { * * Each R5FSS has a cluster-level setting for configuring the processor * subsystem either in a safety/fault-tolerant LockStep mode or a performance - * oriented Split mode. Each R5F core has a number of settings to either + * oriented Split mode on most SoCs. A fewer SoCs support a non-safety mode + * as an alternate for LockStep mode that exercises only a single R5F core + * called Single-CPU mode. Each R5F core has a number of settings to either * enable/disable each of the TCMs, control which TCM appears at the R5F core's * address 0x0. These settings need to be configured before the resets for the * corresponding core are released. These settings are all protected and managed @@ -677,11 +718,13 @@ static const struct rproc_ops k3_r5_rproc_ops = { * the cores are halted before the .prepare() step. * * The function is called from k3_r5_cluster_rproc_init() and is invoked either - * once (in LockStep mode) or twice (in Split mode). Support for LockStep-mode - * is dictated by an eFUSE register bit, and the config settings retrieved from - * DT are adjusted accordingly as per the permitted cluster mode. All cluster - * level settings like Cluster mode and TEINIT (exception handling state - * dictating ARM or Thumb mode) can only be set and retrieved using Core0. + * once (in LockStep mode or Single-CPU modes) or twice (in Split mode). Support + * for LockStep-mode is dictated by an eFUSE register bit, and the config + * settings retrieved from DT are adjusted accordingly as per the permitted + * cluster mode. Another eFUSE register bit dictates if the R5F cluster only + * supports a Single-CPU mode. All cluster level settings like Cluster mode and + * TEINIT (exception handling state dictating ARM or Thumb mode) can only be set + * and retrieved using Core0. * * The function behavior is different based on the cluster mode. The R5F cores * are configured independently as per their individual settings in Split mode. @@ -700,10 +743,16 @@ static int k3_r5_rproc_configure(struct k3_r5_rproc *kproc) u32 set_cfg = 0, clr_cfg = 0; u64 boot_vec = 0; bool lockstep_en; + bool single_cpu; int ret; core0 = list_first_entry(&cluster->cores, struct k3_r5_core, elem); - core = (cluster->mode == CLUSTER_MODE_LOCKSTEP) ? core0 : kproc->core; + if (cluster->mode == CLUSTER_MODE_LOCKSTEP || + cluster->mode == CLUSTER_MODE_SINGLECPU) { + core = core0; + } else { + core = kproc->core; + } ret = ti_sci_proc_get_status(core->tsp, &boot_vec, &cfg, &ctrl, &stat); @@ -713,23 +762,48 @@ static int k3_r5_rproc_configure(struct k3_r5_rproc *kproc) dev_dbg(dev, "boot_vector = 0x%llx, cfg = 0x%x ctrl = 0x%x stat = 0x%x\n", boot_vec, cfg, ctrl, stat); + /* check if only Single-CPU mode is supported on applicable SoCs */ + if (cluster->soc_data->single_cpu_mode) { + single_cpu = + !!(stat & PROC_BOOT_STATUS_FLAG_R5_SINGLECORE_ONLY); + if (single_cpu && cluster->mode == CLUSTER_MODE_SPLIT) { + dev_err(cluster->dev, "split-mode not permitted, force configuring for single-cpu mode\n"); + cluster->mode = CLUSTER_MODE_SINGLECPU; + } + goto config; + } + + /* check conventional LockStep vs Split mode configuration */ lockstep_en = !!(stat & PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED); if (!lockstep_en && cluster->mode == CLUSTER_MODE_LOCKSTEP) { dev_err(cluster->dev, "lockstep mode not permitted, force configuring for split-mode\n"); cluster->mode = CLUSTER_MODE_SPLIT; } +config: /* always enable ARM mode and set boot vector to 0 */ boot_vec = 0x0; if (core == core0) { clr_cfg = PROC_BOOT_CFG_FLAG_R5_TEINIT; - /* - * LockStep configuration bit is Read-only on Split-mode _only_ - * devices and system firmware will NACK any requests with the - * bit configured, so program it only on permitted devices - */ - if (lockstep_en) - clr_cfg |= PROC_BOOT_CFG_FLAG_R5_LOCKSTEP; + if (cluster->soc_data->single_cpu_mode) { + /* + * Single-CPU configuration bit can only be configured + * on Core0 and system firmware will NACK any requests + * with the bit configured, so program it only on + * permitted cores + */ + if (cluster->mode == CLUSTER_MODE_SINGLECPU) + set_cfg = PROC_BOOT_CFG_FLAG_R5_SINGLE_CORE; + } else { + /* + * LockStep configuration bit is Read-only on Split-mode + * _only_ devices and system firmware will NACK any + * requests with the bit configured, so program it only + * on permitted devices + */ + if (lockstep_en) + clr_cfg |= PROC_BOOT_CFG_FLAG_R5_LOCKSTEP; + } } if (core->atcm_enable) @@ -894,12 +968,12 @@ static void k3_r5_reserved_mem_exit(struct k3_r5_rproc *kproc) * cores are usable in Split-mode, but only the Core0 TCMs can be used in * LockStep-mode. The newer revisions of the R5FSS IP maximizes these TCMs by * leveraging the Core1 TCMs as well in certain modes where they would have - * otherwise been unusable (Eg: LockStep-mode on J7200 SoCs). This is done by - * making a Core1 TCM visible immediately after the corresponding Core0 TCM. - * The SoC memory map uses the larger 64 KB sizes for the Core0 TCMs, and the - * dts representation reflects this increased size on supported SoCs. The Core0 - * TCM sizes therefore have to be adjusted to only half the original size in - * Split mode. + * otherwise been unusable (Eg: LockStep-mode on J7200 SoCs, Single-CPU mode on + * AM64x SoCs). This is done by making a Core1 TCM visible immediately after the + * corresponding Core0 TCM. The SoC memory map uses the larger 64 KB sizes for + * the Core0 TCMs, and the dts representation reflects this increased size on + * supported SoCs. The Core0 TCM sizes therefore have to be adjusted to only + * half the original size in Split mode. */ static void k3_r5_adjust_tcm_sizes(struct k3_r5_rproc *kproc) { @@ -909,6 +983,7 @@ static void k3_r5_adjust_tcm_sizes(struct k3_r5_rproc *kproc) struct k3_r5_core *core0; if (cluster->mode == CLUSTER_MODE_LOCKSTEP || + cluster->mode == CLUSTER_MODE_SINGLECPU || !cluster->soc_data->tcm_is_double) return; @@ -987,8 +1062,9 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev) goto err_add; } - /* create only one rproc in lockstep mode */ - if (cluster->mode == CLUSTER_MODE_LOCKSTEP) + /* create only one rproc in lockstep mode or single-cpu mode */ + if (cluster->mode == CLUSTER_MODE_LOCKSTEP || + cluster->mode == CLUSTER_MODE_SINGLECPU) break; } @@ -1020,11 +1096,12 @@ static void k3_r5_cluster_rproc_exit(void *data) struct rproc *rproc; /* - * lockstep mode has only one rproc associated with first core, whereas - * split-mode has two rprocs associated with each core, and requires - * that core1 be powered down first + * lockstep mode and single-cpu modes have only one rproc associated + * with first core, whereas split-mode has two rprocs associated with + * each core, and requires that core1 be powered down first */ - core = (cluster->mode == CLUSTER_MODE_LOCKSTEP) ? + core = (cluster->mode == CLUSTER_MODE_LOCKSTEP || + cluster->mode == CLUSTER_MODE_SINGLECPU) ? list_first_entry(&cluster->cores, struct k3_r5_core, elem) : list_last_entry(&cluster->cores, struct k3_r5_core, elem); @@ -1272,9 +1349,9 @@ static int k3_r5_core_of_init(struct platform_device *pdev) core->tsp = k3_r5_core_of_get_tsp(dev, core->ti_sci); if (IS_ERR(core->tsp)) { + ret = PTR_ERR(core->tsp); dev_err(dev, "failed to construct ti-sci proc control, ret = %d\n", ret); - ret = PTR_ERR(core->tsp); goto err; } @@ -1396,7 +1473,12 @@ static int k3_r5_probe(struct platform_device *pdev) return -ENOMEM; cluster->dev = dev; - cluster->mode = CLUSTER_MODE_LOCKSTEP; + /* + * default to most common efuse configurations - Split-mode on AM64x + * and LockStep-mode on all others + */ + cluster->mode = data->single_cpu_mode ? + CLUSTER_MODE_SPLIT : CLUSTER_MODE_LOCKSTEP; cluster->soc_data = data; INIT_LIST_HEAD(&cluster->cores); @@ -1450,17 +1532,26 @@ static int k3_r5_probe(struct platform_device *pdev) static const struct k3_r5_soc_data am65_j721e_soc_data = { .tcm_is_double = false, .tcm_ecc_autoinit = false, + .single_cpu_mode = false, }; static const struct k3_r5_soc_data j7200_soc_data = { .tcm_is_double = true, .tcm_ecc_autoinit = true, + .single_cpu_mode = false, +}; + +static const struct k3_r5_soc_data am64_soc_data = { + .tcm_is_double = true, + .tcm_ecc_autoinit = true, + .single_cpu_mode = true, }; static const struct of_device_id k3_r5_of_match[] = { { .compatible = "ti,am654-r5fss", .data = &am65_j721e_soc_data, }, { .compatible = "ti,j721e-r5fss", .data = &am65_j721e_soc_data, }, { .compatible = "ti,j7200-r5fss", .data = &j7200_soc_data, }, + { .compatible = "ti,am64-r5fss", .data = &am64_soc_data, }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, k3_r5_of_match); diff --git a/drivers/soc/qcom/smem_state.c b/drivers/soc/qcom/smem_state.c index d2b558438deb..31faf4aa868e 100644 --- a/drivers/soc/qcom/smem_state.c +++ b/drivers/soc/qcom/smem_state.c @@ -151,6 +151,42 @@ void qcom_smem_state_put(struct qcom_smem_state *state) } EXPORT_SYMBOL_GPL(qcom_smem_state_put); +static void devm_qcom_smem_state_release(struct device *dev, void *res) +{ + qcom_smem_state_put(*(struct qcom_smem_state **)res); +} + +/** + * devm_qcom_smem_state_get() - acquire handle to a devres managed state + * @dev: client device pointer + * @con_id: name of the state to lookup + * @bit: flags from the state reference, indicating which bit's affected + * + * Returns handle to the state, or ERR_PTR(). qcom_smem_state_put() is called + * automatically when @dev is removed. + */ +struct qcom_smem_state *devm_qcom_smem_state_get(struct device *dev, + const char *con_id, + unsigned *bit) +{ + struct qcom_smem_state **ptr, *state; + + ptr = devres_alloc(devm_qcom_smem_state_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + state = qcom_smem_state_get(dev, con_id, bit); + if (!IS_ERR(state)) { + *ptr = state; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return state; +} +EXPORT_SYMBOL_GPL(devm_qcom_smem_state_get); + /** * qcom_smem_state_register() - register a new state * @of_node: of_node used for matching client lookups |