remoteproc: imx_rproc: Switch iMX8MN/MP from SMCCC to MMIO
authorMarek Vasut <marex@denx.de>
Mon, 24 Jul 2023 22:24:18 +0000 (00:24 +0200)
committerMathieu Poirier <mathieu.poirier@linaro.org>
Thu, 27 Jul 2023 16:44:17 +0000 (10:44 -0600)
The MX8M CM7 boot via SMC call is problematic, since not all versions
of ATF support this interface. Extend the MMIO support so it can boot
the CM7 on MX8MN/MP instead and discern the two alternatives using DT
compatible strings.

Signed-off-by: Marek Vasut <marex@denx.de>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Link: https://lore.kernel.org/r/20230724222418.163220-2-marex@denx.de
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
drivers/remoteproc/imx_rproc.c
drivers/remoteproc/imx_rproc.h

index 4ee2646..8bb293b 100644 (file)
 #define IMX7D_M4_STOP                  (IMX7D_ENABLE_M4 | IMX7D_SW_M4C_RST | \
                                         IMX7D_SW_M4C_NON_SCLR_RST)
 
+#define IMX8M_M7_STOP                  (IMX7D_ENABLE_M4 | IMX7D_SW_M4C_RST)
+#define IMX8M_M7_POLL                  IMX7D_ENABLE_M4
+
+#define IMX8M_GPR22                    0x58
+#define IMX8M_GPR22_CM7_CPUWAIT                BIT(0)
+
 /* Address: 0x020D8000 */
 #define IMX6SX_SRC_SCR                 0x00
 #define IMX6SX_ENABLE_M4               BIT(22)
@@ -91,6 +97,7 @@ static int imx_rproc_detach_pd(struct rproc *rproc);
 struct imx_rproc {
        struct device                   *dev;
        struct regmap                   *regmap;
+       struct regmap                   *gpr;
        struct rproc                    *rproc;
        const struct imx_rproc_dcfg     *dcfg;
        struct imx_rproc_mem            mem[IMX_RPROC_MEM_MAX];
@@ -285,6 +292,18 @@ static const struct imx_rproc_att imx_rproc_att_imx6sx[] = {
        { 0x80000000, 0x80000000, 0x60000000, 0 },
 };
 
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = {
+       .src_reg        = IMX7D_SRC_SCR,
+       .src_mask       = IMX7D_M4_RST_MASK,
+       .src_start      = IMX7D_M4_START,
+       .src_stop       = IMX8M_M7_STOP,
+       .gpr_reg        = IMX8M_GPR22,
+       .gpr_wait       = IMX8M_GPR22_CM7_CPUWAIT,
+       .att            = imx_rproc_att_imx8mn,
+       .att_size       = ARRAY_SIZE(imx_rproc_att_imx8mn),
+       .method         = IMX_RPROC_MMIO,
+};
+
 static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = {
        .att            = imx_rproc_att_imx8mn,
        .att_size       = ARRAY_SIZE(imx_rproc_att_imx8mn),
@@ -365,8 +384,14 @@ static int imx_rproc_start(struct rproc *rproc)
 
        switch (dcfg->method) {
        case IMX_RPROC_MMIO:
-               ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask,
-                                        dcfg->src_start);
+               if (priv->gpr) {
+                       ret = regmap_clear_bits(priv->gpr, dcfg->gpr_reg,
+                                               dcfg->gpr_wait);
+               } else {
+                       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);
@@ -395,6 +420,16 @@ static int imx_rproc_stop(struct rproc *rproc)
 
        switch (dcfg->method) {
        case IMX_RPROC_MMIO:
+               if (priv->gpr) {
+                       ret = regmap_set_bits(priv->gpr, dcfg->gpr_reg,
+                                             dcfg->gpr_wait);
+                       if (ret) {
+                               dev_err(priv->dev,
+                                       "Failed to quiescence M4 platform!\n");
+                               return ret;
+                       }
+               }
+
                ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask,
                                         dcfg->src_stop);
                break;
@@ -992,6 +1027,10 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv)
                break;
        }
 
+       priv->gpr = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,iomuxc-gpr");
+       if (IS_ERR(priv->gpr))
+               priv->gpr = NULL;
+
        regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
        if (IS_ERR(regmap)) {
                dev_err(dev, "failed to find syscon\n");
@@ -1001,6 +1040,19 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv)
        priv->regmap = regmap;
        regmap_attach_dev(dev, regmap, &config);
 
+       if (priv->gpr) {
+               ret = regmap_read(priv->gpr, dcfg->gpr_reg, &val);
+               if (val & dcfg->gpr_wait) {
+                       /*
+                        * After cold boot, the CM indicates its in wait
+                        * state, but not fully powered off. Power it off
+                        * fully so firmware can be loaded into it.
+                        */
+                       imx_rproc_stop(priv->rproc);
+                       return 0;
+               }
+       }
+
        ret = regmap_read(regmap, dcfg->src_reg, &val);
        if (ret) {
                dev_err(dev, "Failed to read src\n");
@@ -1142,6 +1194,8 @@ static const struct of_device_id imx_rproc_of_match[] = {
        { .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,imx8mn-cm7-mmio", .data = &imx_rproc_cfg_imx8mn_mmio },
+       { .compatible = "fsl,imx8mp-cm7-mmio", .data = &imx_rproc_cfg_imx8mn_mmio },
        { .compatible = "fsl,imx8qxp-cm4", .data = &imx_rproc_cfg_imx8qxp },
        { .compatible = "fsl,imx8qm-cm4", .data = &imx_rproc_cfg_imx8qm },
        { .compatible = "fsl,imx8ulp-cm33", .data = &imx_rproc_cfg_imx8ulp },
index 1c7e212..79a1b89 100644 (file)
@@ -31,6 +31,8 @@ struct imx_rproc_dcfg {
        u32                             src_mask;
        u32                             src_start;
        u32                             src_stop;
+       u32                             gpr_reg;
+       u32                             gpr_wait;
        const struct imx_rproc_att      *att;
        size_t                          att_size;
        enum imx_rproc_method           method;