hrtimer: Report offline hrtimer enqueue
[platform/kernel/linux-rpi.git] / drivers / remoteproc / imx_rproc.c
index 0ab840d..8bb293b 100644 (file)
@@ -13,9 +13,9 @@
 #include <linux/mailbox_client.h>
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_reserved_mem.h>
-#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
 #include <linux/regmap.h>
 #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;
@@ -725,13 +760,22 @@ static int imx_rproc_addr_init(struct imx_rproc *priv,
        return 0;
 }
 
+static int imx_rproc_notified_idr_cb(int id, void *ptr, void *data)
+{
+       struct rproc *rproc = data;
+
+       rproc_vq_interrupt(rproc, id);
+
+       return 0;
+}
+
 static void imx_rproc_vq_work(struct work_struct *work)
 {
        struct imx_rproc *priv = container_of(work, struct imx_rproc,
                                              rproc_work);
+       struct rproc *rproc = priv->rproc;
 
-       rproc_vq_interrupt(priv->rproc, 0);
-       rproc_vq_interrupt(priv->rproc, 1);
+       idr_for_each(&rproc->notifyids, imx_rproc_notified_idr_cb, rproc);
 }
 
 static void imx_rproc_rx_callback(struct mbox_client *cl, void *msg)
@@ -983,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");
@@ -992,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");
@@ -1112,7 +1173,7 @@ err_put_rproc:
        return ret;
 }
 
-static int imx_rproc_remove(struct platform_device *pdev)
+static void imx_rproc_remove(struct platform_device *pdev)
 {
        struct rproc *rproc = platform_get_drvdata(pdev);
        struct imx_rproc *priv = rproc->priv;
@@ -1123,8 +1184,6 @@ static int imx_rproc_remove(struct platform_device *pdev)
        imx_rproc_free_mbox(rproc);
        destroy_workqueue(priv->workqueue);
        rproc_free(rproc);
-
-       return 0;
 }
 
 static const struct of_device_id imx_rproc_of_match[] = {
@@ -1135,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 },
@@ -1145,7 +1206,7 @@ MODULE_DEVICE_TABLE(of, imx_rproc_of_match);
 
 static struct platform_driver imx_rproc_driver = {
        .probe = imx_rproc_probe,
-       .remove = imx_rproc_remove,
+       .remove_new = imx_rproc_remove,
        .driver = {
                .name = "imx-rproc",
                .of_match_table = imx_rproc_of_match,