Integrate OP-TEE-controlled firmware loading into stm32_rproc
adding support for the st,rproc-tee devicetree property.

When st,rproc-tee is present, the driver:
- parses the backend phandle + ID from DT and validates it
- uses the remoteproc_tee operation set and registration path
- keeps reset/holdboot handling only for the non-TEE case
- uses a TEE-specific flow.

Notice that the attach/detach is not yet supported and should be part
of a separate patchset.

Signed-off-by: Arnaud Pouliquen <[email protected]>
---
V21 updates:
- reapply the V19 patch as the stm32_rproc-tee  driver can no more
  be used.
- update v19 patch to support the st,rproc-tee phandle.
- rework the commit message.
---
 drivers/remoteproc/stm32_rproc.c | 167 +++++++++++++++++++++++--------
 1 file changed, 123 insertions(+), 44 deletions(-)

diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
index 4bcd6a784935..61d89f3a78b1 100644
--- a/drivers/remoteproc/stm32_rproc.c
+++ b/drivers/remoteproc/stm32_rproc.c
@@ -18,6 +18,7 @@
 #include <linux/pm_wakeirq.h>
 #include <linux/regmap.h>
 #include <linux/remoteproc.h>
+#include <linux/remoteproc_tee.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
@@ -89,6 +90,7 @@ struct stm32_rproc {
        struct stm32_rproc_mem *rmems;
        struct stm32_mbox mb[MBOX_NB_MBX];
        struct workqueue_struct *workqueue;
+       struct of_phandle_args tee_phandle;
        bool hold_boot_smc;
        void __iomem *rsc_va;
 };
@@ -255,6 +257,19 @@ static int stm32_rproc_release(struct rproc *rproc)
        return 0;
 }
 
+static int stm32_rproc_tee_stop(struct rproc *rproc)
+{
+       int err;
+
+       stm32_rproc_request_shutdown(rproc);
+
+       err = rproc_tee_stop(rproc);
+       if (err)
+               return err;
+
+       return stm32_rproc_release(rproc);
+}
+
 static int stm32_rproc_prepare(struct rproc *rproc)
 {
        struct device *dev = rproc->dev.parent;
@@ -683,6 +698,17 @@ static const struct rproc_ops st_rproc_ops = {
        .get_boot_addr  = rproc_elf_get_boot_addr,
 };
 
+static const struct rproc_ops st_rproc_tee_ops = {
+       .prepare        = stm32_rproc_prepare,
+       .start          = rproc_tee_start,
+       .stop           = stm32_rproc_tee_stop,
+       .kick           = stm32_rproc_kick,
+       .load           = rproc_tee_load_fw,
+       .parse_fw       = rproc_tee_parse_fw,
+       .find_loaded_rsc_table = rproc_tee_find_loaded_rsc_table,
+       .release_fw     = rproc_tee_release_fw,
+};
+
 static const struct of_device_id stm32_rproc_match[] = {
        { .compatible = "st,stm32mp1-m4" },
        {},
@@ -716,6 +742,7 @@ static int stm32_rproc_parse_dt(struct platform_device 
*pdev,
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
+       struct of_phandle_args tee_phandle;
        struct stm32_syscon tz;
        unsigned int tzen;
        int err, irq;
@@ -741,51 +768,69 @@ static int stm32_rproc_parse_dt(struct platform_device 
*pdev,
                dev_info(dev, "wdg irq registered\n");
        }
 
-       ddata->rst = devm_reset_control_get_optional(dev, "mcu_rst");
-       if (!ddata->rst) {
-               /* Try legacy fallback method: get it by index */
-               ddata->rst = devm_reset_control_get_by_index(dev, 0);
+       if (of_find_property(np, "st,rproc-tee", NULL)) {
+               err = of_parse_phandle_with_fixed_args(np, "st,rproc-tee",
+                                                      1, 0, &tee_phandle);
+               if (err)
+                       return dev_err_probe(dev, err,
+                                            "failed to parse st,rproc-tee\n");
+
+               if (!IS_ENABLED(CONFIG_REMOTEPROC_TEE)) {
+                       of_node_put(tee_phandle.np);
+                       return dev_err_probe(dev, -ENODEV,
+                                            "st,rproc-tee requires 
REMOTEPROC_TEE support\n");
+               }
+
+               ddata->tee_phandle = tee_phandle;
        }
-       if (IS_ERR(ddata->rst))
-               return dev_err_probe(dev, PTR_ERR(ddata->rst),
-                                    "failed to get mcu_reset\n");
 
-       /*
-        * Three ways to manage the hold boot
-        * - using SCMI: the hold boot is managed as a reset
-        *    The DT "reset-mames" property should be defined with 2 items:
-        *        reset-names = "mcu_rst", "hold_boot";
-        * - using SMC call (deprecated): use SMC reset interface
-        *    The DT "reset-mames" property is optional, "st,syscfg-tz" is 
required
-        * - default(no SCMI, no SMC): the hold boot is managed as a syscon 
register
-        *    The DT "reset-mames" property is optional, "st,syscfg-holdboot" 
is required
-        */
+       if (!ddata->tee_phandle.np) {
+               ddata->rst = devm_reset_control_get_optional(dev, "mcu_rst");
+               if (!ddata->rst) {
+                       /* Try legacy fallback method: get it by index */
+                       ddata->rst = devm_reset_control_get_by_index(dev, 0);
+               }
+               if (IS_ERR(ddata->rst))
+                       return dev_err_probe(dev, PTR_ERR(ddata->rst),
+                                       "failed to get mcu_reset\n");
 
-       ddata->hold_boot_rst = devm_reset_control_get_optional(dev, 
"hold_boot");
-       if (IS_ERR(ddata->hold_boot_rst))
-               return dev_err_probe(dev, PTR_ERR(ddata->hold_boot_rst),
-                                    "failed to get hold_boot reset\n");
+               /*
+                * Three ways to manage the hold boot
+                * - using SCMI: the hold boot is managed as a reset
+                *    The DT "reset-mames" property should be defined with 2 
items:
+                *        reset-names = "mcu_rst", "hold_boot";
+                * - using SMC call (deprecated): use SMC reset interface
+                *    The DT "reset-mames" property is optional, "st,syscfg-tz" 
is required
+                * - default(no SCMI, no SMC): the hold boot is managed as a 
syscon register
+                *    The DT "reset-mames" property is optional, 
"st,syscfg-holdboot" is required
+                */
 
-       if (!ddata->hold_boot_rst && IS_ENABLED(CONFIG_HAVE_ARM_SMCCC)) {
-               /* Manage the MCU_BOOT using SMC call */
-               err = stm32_rproc_get_syscon(np, "st,syscfg-tz", &tz);
-               if (!err) {
-                       err = regmap_read(tz.map, tz.reg, &tzen);
-                       if (err) {
-                               dev_err(dev, "failed to read tzen\n");
-                               return err;
+               ddata->hold_boot_rst = devm_reset_control_get_optional(dev, 
"hold_boot");
+               if (IS_ERR(ddata->hold_boot_rst))
+                       return dev_err_probe(dev, PTR_ERR(ddata->hold_boot_rst),
+                                       "failed to get hold_boot reset\n");
+
+               if (!ddata->hold_boot_rst && IS_ENABLED(CONFIG_HAVE_ARM_SMCCC)) 
{
+                       /* Manage the MCU_BOOT using SMC call */
+                       err = stm32_rproc_get_syscon(np, "st,syscfg-tz", &tz);
+                       if (!err) {
+                               err = regmap_read(tz.map, tz.reg, &tzen);
+                               if (err) {
+                                       dev_err(dev, "failed to read tzen\n");
+                                       return err;
+                               }
+                               ddata->hold_boot_smc = tzen & tz.mask;
                        }
-                       ddata->hold_boot_smc = tzen & tz.mask;
                }
-       }
 
-       if (!ddata->hold_boot_rst && !ddata->hold_boot_smc) {
-               /* Default: hold boot manage it through the syscon controller */
-               err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot",
-                                            &ddata->hold_boot);
-               if (err) {
-                       dev_err(dev, "failed to get hold boot\n");
-                       return err;
+               if (!ddata->hold_boot_rst && !ddata->hold_boot_smc) {
+                       /* Default: hold boot manage it through the syscon 
controller */
+                       err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot",
+                                                    &ddata->hold_boot);
+                       if (err) {
+                               dev_err(dev, "failed to get hold boot\n");
+                               return err;
+                       }
                }
        }
 
@@ -857,18 +902,31 @@ static int stm32_rproc_probe(struct platform_device *pdev)
        if (ret < 0 && ret != -EINVAL)
                return ret;
 
-       rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, fw_name, 
sizeof(*ddata));
+       if (of_find_property(np, "st,rproc-tee", NULL))
+               rproc = devm_rproc_alloc(dev, np->name, &st_rproc_tee_ops, 
fw_name,
+                                        sizeof(*ddata));
+       else
+               rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, fw_name,
+                                        sizeof(*ddata));
+
        if (!rproc)
                return -ENOMEM;
 
        ddata = rproc->priv;
-
        rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
 
        ret = stm32_rproc_parse_dt(pdev, ddata, &rproc->auto_boot);
        if (ret)
                goto free_rproc;
 
+       if (ddata->tee_phandle.np &&
+           !of_device_is_available(ddata->tee_phandle.np)) {
+               of_node_put(ddata->tee_phandle.np);
+               ddata->tee_phandle.np = NULL;
+               ret = -EPROBE_DEFER;
+               goto free_rproc;
+       }
+
        ret = stm32_rproc_of_memory_translations(pdev, ddata);
        if (ret)
                goto free_rproc;
@@ -877,8 +935,14 @@ static int stm32_rproc_probe(struct platform_device *pdev)
        if (ret)
                goto free_rproc;
 
-       if (state == M4_STATE_CRUN)
+       if (state == M4_STATE_CRUN) {
+               if (ddata->tee_phandle.np) {
+                       dev_err(dev, "TEE support not yet compatible with 
attached state\n");
+                       ret = -EINVAL;
+                       goto free_rproc;
+               }
                rproc->state = RPROC_DETACHED;
+       }
 
        rproc->has_iommu = false;
        ddata->workqueue = create_workqueue(dev_name(dev));
@@ -894,10 +958,12 @@ static int stm32_rproc_probe(struct platform_device *pdev)
        if (ret)
                goto free_wkq;
 
-       ret = rproc_add(rproc);
+       if (ddata->tee_phandle.np)
+               ret = rproc_tee_register(dev, rproc, &ddata->tee_phandle);
+       else
+               ret = rproc_add(rproc);
        if (ret)
                goto free_mb;
-
        return 0;
 
 free_mb:
@@ -911,6 +977,11 @@ static int stm32_rproc_probe(struct platform_device *pdev)
                dev_pm_clear_wake_irq(dev);
                device_init_wakeup(dev, false);
        }
+       if (ddata->tee_phandle.np) {
+               of_node_put(ddata->tee_phandle.np);
+               ddata->tee_phandle.np = NULL;
+       }
+
        return ret;
 }
 
@@ -919,11 +990,11 @@ static void stm32_rproc_remove(struct platform_device 
*pdev)
        struct rproc *rproc = platform_get_drvdata(pdev);
        struct stm32_rproc *ddata = rproc->priv;
        struct device *dev = &pdev->dev;
+       struct device_node *tee_np = ddata->tee_phandle.np;
 
        if (atomic_read(&rproc->power) > 0)
                rproc_shutdown(rproc);
 
-       rproc_del(rproc);
        stm32_rproc_free_mbox(rproc);
        destroy_workqueue(ddata->workqueue);
 
@@ -931,6 +1002,14 @@ static void stm32_rproc_remove(struct platform_device 
*pdev)
                dev_pm_clear_wake_irq(dev);
                device_init_wakeup(dev, false);
        }
+
+       if (tee_np) {
+               ddata->tee_phandle.np = NULL;
+               rproc_tee_unregister(dev, rproc);
+               of_node_put(tee_np);
+       } else {
+               rproc_del(rproc);
+       }
 }
 
 static int stm32_rproc_suspend(struct device *dev)
-- 
2.43.0


Reply via email to