MLK-13994-1: ARM: imx7ulp: add acknowledgement for vlls message notification
authorRobin Gong <yibin.gong@nxp.com>
Fri, 17 Feb 2017 07:48:56 +0000 (15:48 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 20:10:44 +0000 (15:10 -0500)
Now, M4 rpmsg add free buffer feature that free the reciever buffer and update
some rpmsg structure data in share memory(DDR) once M4 receive the message from
A7 side, that means M4 will access DDR after it receive the vlls message(A7 enter
VLLS mode quickly), thus M4 hang because DDR in slef-refresh...
This patch move the vlls message notification ahead to driver suspend and add
acknowledgement to make sure no any DDR access comes from M4 side after A7 enter
suspend.

Signed-off-by: Robin Gong <yibin.gong@nxp.com>
arch/arm/mach-imx/common.h
arch/arm/mach-imx/pm-imx7ulp.c
arch/arm/mach-imx/pm-rpmsg.c

index 6c0e83d..cf289b7 100644 (file)
@@ -203,7 +203,6 @@ void imx7ulp_cpu_resume(void);
 void imx6_suspend(void __iomem *ocram_vbase);
 void imx7_suspend(void __iomem *ocram_vbase);
 void imx7ulp_suspend(void __iomem *ocram_vbase);
-void pm_vlls_notify_m4(bool enter);
 #else
 static inline void v7_cpu_resume(void) {}
 static inline void ca7_cpu_resume(void) {}
@@ -213,7 +212,6 @@ static inline void imx7ulp_cpu_resume(void) {}
 static inline void imx6_suspend(void __iomem *ocram_vbase) {}
 static inline void imx7_suspend(void __iomem *ocram_vbase) {}
 static inline void imx7ulp_suspend(void __iomem *ocram_vbase) {}
-void pm_vlls_notify_m4(bool enter) {}
 #endif
 void pm_shutdown_notify_m4(void);
 
index cf2520a..1f620fe 100644 (file)
@@ -451,7 +451,6 @@ static int imx7ulp_pm_enter(suspend_state_t state)
                imx7ulp_set_lpm(RUN);
                break;
        case PM_SUSPEND_MEM:
-               pm_vlls_notify_m4(true);
                imx7ulp_gpio_save();
                imx7ulp_scg1_save();
                imx7ulp_pcc2_save();
@@ -472,7 +471,6 @@ static int imx7ulp_pm_enter(suspend_state_t state)
                imx7ulp_tpm_restore();
                imx7ulp_iomuxc_restore();
                imx7ulp_set_lpm(RUN);
-               pm_vlls_notify_m4(false);
                break;
        default:
                return -EINVAL;
index fb5e0fb..e6f02d9 100644 (file)
@@ -28,7 +28,8 @@
 
 #define RPMSG_TIMEOUT 1000
 
-#define PM_RPMSG_TYPE          2
+#define PM_RPMSG_TYPE          0
+#define HEATBEAT_RPMSG_TYPE    2
 
 enum pm_rpmsg_cmd {
        PM_RPMSG_MODE,
@@ -52,6 +53,7 @@ struct pm_rpmsg_info {
        struct pm_rpmsg_data *msg;
        struct pm_qos_request pm_qos_req;
        struct notifier_block restart_handler;
+       struct completion cmd_complete;
 };
 
 static struct pm_rpmsg_info pm_rpmsg;
@@ -64,7 +66,7 @@ struct pm_rpmsg_data {
 } __attribute__ ((packed));
 
 static int pm_send_message(struct pm_rpmsg_data *msg,
-                       struct pm_rpmsg_info *info, bool susp)
+                       struct pm_rpmsg_info *info, bool ack)
 {
        int err;
 
@@ -73,20 +75,42 @@ static int pm_send_message(struct pm_rpmsg_data *msg,
                        "rpmsg channel not ready, m4 image ready?\n");
                return -EINVAL;
        }
-       if (!susp)
-               pm_qos_add_request(&info->pm_qos_req,
+       pm_qos_add_request(&info->pm_qos_req,
                        PM_QOS_CPU_DMA_LATENCY, 0);
 
+       reinit_completion(&info->cmd_complete);
+
        err = rpmsg_send(info->rpdev->ept, (void *)msg,
                            sizeof(struct pm_rpmsg_data));
 
-       if (!susp)
-               pm_qos_remove_request(&info->pm_qos_req);
+       pm_qos_remove_request(&info->pm_qos_req);
+
+       if (err) {
+               dev_err(&info->rpdev->dev, "rpmsg_send failed: %d\n", err);
+               return err;
+       }
+
+       if (ack) {
+               err = wait_for_completion_timeout(&info->cmd_complete,
+                                       msecs_to_jiffies(RPMSG_TIMEOUT));
+               if (!err) {
+                       dev_err(&info->rpdev->dev, "rpmsg_send timeout!\n");
+                       return -ETIMEDOUT;
+               }
+
+               if (info->msg->data != 0) {
+                       dev_err(&info->rpdev->dev, "rpmsg not ack %d!\n",
+                               info->msg->data);
+                       return -EINVAL;
+               }
+
+               err = 0;
+       }
 
        return err;
 }
 
-void pm_vlls_notify_m4(bool enter)
+static int pm_vlls_notify_m4(bool enter)
 {
        struct pm_rpmsg_data msg;
 
@@ -97,7 +121,7 @@ void pm_vlls_notify_m4(bool enter)
        msg.header.cmd = PM_RPMSG_MODE;
        msg.data = enter ? PM_RPMSG_VLLS : PM_RPMSG_RUN;
 
-       pm_send_message(&msg, &pm_rpmsg, true);
+       return pm_send_message(&msg, &pm_rpmsg, true);
 }
 
 void pm_shutdown_notify_m4(void)
@@ -111,7 +135,7 @@ void pm_shutdown_notify_m4(void)
        msg.header.cmd = PM_RPMSG_MODE;
        msg.data = PM_RPMSG_SHUTDOWN;
 
-       pm_send_message(&msg, &pm_rpmsg, false);
+       pm_send_message(&msg, &pm_rpmsg, true);
 
 }
 
@@ -126,7 +150,7 @@ void pm_reboot_notify_m4(void)
        msg.header.cmd = PM_RPMSG_MODE;
        msg.data = PM_RPMSG_REBOOT;
 
-       pm_send_message(&msg, &pm_rpmsg, false);
+       pm_send_message(&msg, &pm_rpmsg, true);
 
 }
 
@@ -137,10 +161,9 @@ static void pm_heart_beat_work_handler(struct work_struct *work)
        msg.header.cate = IMX_RMPSG_LIFECYCLE;
        msg.header.major = IMX_RMPSG_MAJOR;
        msg.header.minor = IMX_RMPSG_MINOR;
-       msg.header.type = PM_RPMSG_TYPE;
+       msg.header.type = HEATBEAT_RPMSG_TYPE;
        msg.header.cmd = PM_RPMSG_HEART_BEAT;
        msg.data = 0;
-
        pm_send_message(&msg, &pm_rpmsg, false);
 
        schedule_delayed_work(&heart_beat_work,
@@ -164,6 +187,8 @@ static int pm_rpmsg_probe(struct rpmsg_device *rpdev)
        dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
                        rpdev->src, rpdev->dst);
 
+       init_completion(&pm_rpmsg.cmd_complete);
+
        INIT_DELAYED_WORK(&heart_beat_work,
                pm_heart_beat_work_handler);
 
@@ -184,6 +209,12 @@ static int pm_rpmsg_probe(struct rpmsg_device *rpdev)
 static int pm_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
                        void *priv, u32 src)
 {
+       struct pm_rpmsg_data *msg = (struct pm_rpmsg_data *)data;
+
+       pm_rpmsg.msg = msg;
+
+       complete(&pm_rpmsg.cmd_complete);
+
        return 0;
 }
 
@@ -206,12 +237,45 @@ static struct rpmsg_driver pm_rpmsg_driver = {
        .remove         = pm_rpmsg_remove,
 };
 
-static int __init pm_rpmsg_init(void)
+#ifdef CONFIG_PM_SLEEP
+static int pm_heartbeat_suspend(struct device *dev)
 {
+       return pm_vlls_notify_m4(true);
+}
+
+static int pm_heartbeat_resume(struct device *dev)
+{
+       return pm_vlls_notify_m4(false);
+}
+#endif
+
+static int pm_heartbeat_probe(struct platform_device *pdev)
+{
+       platform_set_drvdata(pdev, &pm_rpmsg);
+
        return register_rpmsg_driver(&pm_rpmsg_driver);
 }
 
-module_init(pm_rpmsg_init);
+static const struct of_device_id pm_heartbeat_id[] = {
+       {"fsl,heartbeat-rpmsg",},
+       {},
+};
+MODULE_DEVICE_TABLE(of, pm_heartbeat_id);
+
+static SIMPLE_DEV_PM_OPS(pm_heartbeat_ops, pm_heartbeat_suspend,
+                        pm_heartbeat_resume);
+
+static struct platform_driver pm_heartbeat_driver = {
+       .driver = {
+               .name = "heartbeat-rpmsg",
+               .owner = THIS_MODULE,
+               .of_match_table = pm_heartbeat_id,
+               .pm = &pm_heartbeat_ops,
+               },
+       .probe = pm_heartbeat_probe,
+};
+
+module_platform_driver(pm_heartbeat_driver);
 
 MODULE_DESCRIPTION("Freescale PM rpmsg driver");
 MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");