summaryrefslogtreecommitdiff
path: root/drivers/rpmsg
diff options
context:
space:
mode:
authorRobin Gong <yibin.gong@nxp.com>2019-01-09 22:59:01 +0800
committerJason Liu <jason.hui.liu@nxp.com>2019-02-12 10:35:52 +0800
commitaa619cf5b4836de66738cf876c8335508e052dc4 (patch)
tree8059e1798e45e6fd4b843ed9b21a7b2298a65271 /drivers/rpmsg
parentac10d4fb898113e0c8de7fe567f2ac0a6d50eb6c (diff)
MLK-20691-3 rpmsg: imx_rpmsg: add partition reset support
unregister all rpmsg devices and kick off ready notifyication again to restore back rpmsg communications after M4 partion reset. Signed-off-by: Robin Gong <yibin.gong@nxp.com> Acked-by: Richard Zhu <hongxing.zhu@nxp.com>
Diffstat (limited to 'drivers/rpmsg')
-rw-r--r--drivers/rpmsg/imx_rpmsg.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/drivers/rpmsg/imx_rpmsg.c b/drivers/rpmsg/imx_rpmsg.c
index 3312a9aaaf84..ced9c664af9d 100644
--- a/drivers/rpmsg/imx_rpmsg.c
+++ b/drivers/rpmsg/imx_rpmsg.c
@@ -13,6 +13,7 @@
*/
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -34,6 +35,7 @@
#include <linux/mx8_mu.h>
#include <soc/imx8/sc/sci.h>
#include <soc/imx8/sc/svc/irq/api.h>
+#include "rpmsg_internal.h"
enum imx_rpmsg_variants {
IMX6SX,
@@ -486,6 +488,48 @@ static int imx_rpmsg_mu_init(struct imx_rpmsg_vproc *rpdev)
return ret;
}
+static int imx_unregister_rpmsg(struct device *dev,
+ void *data)
+{
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+ struct rpmsg_channel_info chinfo;
+ int ret;
+ struct virtio_device *vdev = (struct virtio_device *)data;
+
+ chinfo.src = rpdev->src;
+ chinfo.dst = rpdev->dst;
+ strncpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE);
+ rpdev->announce = rpdev->src != RPMSG_ADDR_ANY;
+
+ ret = rpmsg_unregister_device(&vdev->dev, &chinfo);
+ if (ret)
+ dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret);
+
+ return ret;
+}
+
+void imx_rpmsg_restore(struct imx_rpmsg_vproc *rpdev)
+{
+ int i;
+ unsigned int mu_rpmsg = 0;
+ int vdev_nums = rpdev->vdev_nums;
+
+ for (i = 0; i < vdev_nums; i++) {
+ /* unregister all rpmsg channels */
+ device_for_each_child(&rpdev->ivdev[i].vdev.dev,
+ &rpdev->ivdev[i].vdev,
+ imx_unregister_rpmsg);
+
+ /* Wait a while for remote bootup */
+ if (!i)
+ usleep_range(10000, 20000);
+
+ /* Kick-off remote again */
+ MU_SendMessageTimeout(rpdev->mu_base, 1, mu_rpmsg << 16, 200);
+ mu_rpmsg += 2;
+ }
+}
+
static int imx_rpmsg_partion_notify0(struct notifier_block *nb,
unsigned long event, void *group)
{
@@ -496,6 +540,7 @@ static int imx_rpmsg_partion_notify0(struct notifier_block *nb,
(*(sc_irq_group_t *)group == SC_IRQ_GROUP_REBOOTED)))
return 0;
+ imx_rpmsg_restore(rpdev);
pr_info("Patition%d reset!\n", rpdev->mub_partition);
return 0;
@@ -511,6 +556,7 @@ static int imx_rpmsg_partion_notify1(struct notifier_block *nb,
(*(sc_irq_group_t *)group == SC_IRQ_GROUP_REBOOTED)))
return 0;
+ imx_rpmsg_restore(rpdev);
pr_info("Patition%d reset!\n", rpdev->mub_partition);
return 0;