MLK-16586-3 rpmsg: imx: enable multi-core rpmsg
authorRichard Zhu <hongxing.zhu@nxp.com>
Mon, 16 Oct 2017 02:18:07 +0000 (10:18 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 20:38:54 +0000 (15:38 -0500)
- Init multi-core mu power and clk.
- enable the multi-core rpmsg support

BuildInfo:
- SCFW a6fd9a48, IMX-MKIMAGE 0, ATF 0
- U-Boot 2017.03-imx_v2017.03_4.9.11_imx8_alpha+g258936c

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
Reviewed-by: Robin Gong <yibin.gong@nxp.com>
Tested-by: Andy Duan <fugang.duan@nxp.com>
drivers/rpmsg/imx_rpmsg.c
drivers/rpmsg/imx_rpmsg_pingpong.c
include/linux/imx_rpmsg.h

index fac6420..5265e0a 100644 (file)
@@ -37,6 +37,7 @@ enum imx_rpmsg_variants {
        IMX7D,
        IMX7ULP,
        IMX8QXP,
+       IMX8QM,
 };
 static enum imx_rpmsg_variants variant;
 
@@ -55,24 +56,16 @@ struct imx_rpmsg_vproc {
        int vdev_nums;
 #define MAX_VDEV_NUMS  7
        struct imx_virdev ivdev[MAX_VDEV_NUMS];
-};
-
-struct imx_mu_rpmsg_box {
-       const char *name;
+       void __iomem *mu_base;
+       struct delayed_work rpmsg_work;
        struct blocking_notifier_head notifier;
-};
-
-static struct imx_mu_rpmsg_box mu_rpmsg_box = {
-       .name   = "m4",
-};
-
 #define MAX_NUM 10     /* enlarge it if overflow happen */
-
-static void __iomem *mu_base;
-static u32 m4_message[MAX_NUM];
-static u32 in_idx, out_idx;
-static DEFINE_SPINLOCK(mu_lock);
-static struct delayed_work rpmsg_work;
+       u32 m4_message[MAX_NUM];
+       u32 in_idx;
+       u32 out_idx;
+       u32 core_id;
+       spinlock_t mu_lock;
+};
 
 /*
  * For now, allocate 256 buffers of 512 bytes for each side. each buffer
@@ -128,7 +121,7 @@ static bool imx_rpmsg_notify(struct virtqueue *vq)
        mu_rpmsg = rpvq->vq_id << 16;
        mutex_lock(&rpvq->rpdev->lock);
        /* send the index of the triggered virtqueue as the mu payload */
-       MU_SendMessage(mu_base, 1, mu_rpmsg);
+       MU_SendMessage(rpvq->rpdev->mu_base, 1, mu_rpmsg);
        mutex_unlock(&rpvq->rpdev->lock);
 
        return true;
@@ -164,29 +157,24 @@ static int imx_mu_rpmsg_callback(struct notifier_block *this,
        return NOTIFY_DONE;
 }
 
-int imx_mu_rpmsg_register_nb(const char *name, struct notifier_block *nb)
+static int imx_mu_rpmsg_register_nb(struct imx_rpmsg_vproc *rpdev,
+               struct notifier_block *nb)
 {
-       if ((name == NULL) || (nb == NULL))
+       if ((rpdev == NULL) || (nb == NULL))
                return -EINVAL;
 
-       if (!strcmp(mu_rpmsg_box.name, name))
-               blocking_notifier_chain_register(&(mu_rpmsg_box.notifier), nb);
-       else
-               return -ENOENT;
+       blocking_notifier_chain_register(&(rpdev->notifier), nb);
 
        return 0;
 }
 
-int imx_mu_rpmsg_unregister_nb(const char *name, struct notifier_block *nb)
+static int imx_mu_rpmsg_unregister_nb(struct imx_rpmsg_vproc *rpdev,
+               struct notifier_block *nb)
 {
-       if ((name == NULL) || (nb == NULL))
+       if ((rpdev == NULL) || (nb == NULL))
                return -EINVAL;
 
-       if (!strcmp(mu_rpmsg_box.name, name))
-               blocking_notifier_chain_unregister(&(mu_rpmsg_box.notifier),
-                               nb);
-       else
-               return -ENOENT;
+       blocking_notifier_chain_unregister(&(rpdev->notifier), nb);
 
        return 0;
 }
@@ -262,8 +250,7 @@ static void imx_rpmsg_del_vqs(struct virtio_device *vdev)
        }
 
        if (&virdev->nb)
-               imx_mu_rpmsg_unregister_nb((const char *)rpdev->rproc_name,
-                               &virdev->nb);
+               imx_mu_rpmsg_unregister_nb(rpdev, &virdev->nb);
 }
 
 static int imx_rpmsg_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
@@ -291,7 +278,7 @@ static int imx_rpmsg_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
        virdev->num_of_vqs = nvqs;
 
        virdev->nb.notifier_call = imx_mu_rpmsg_callback;
-       imx_mu_rpmsg_register_nb((const char *)rpdev->rproc_name, &virdev->nb);
+       imx_mu_rpmsg_register_nb(rpdev, &virdev->nb);
 
        return 0;
 
@@ -334,6 +321,9 @@ static struct imx_rpmsg_vproc imx_rpmsg_vprocs[] = {
        {
                .rproc_name     = "m4",
        },
+       {
+               .rproc_name     = "m4",
+       },
 };
 
 static const struct of_device_id imx_rpmsg_dt_ids[] = {
@@ -341,6 +331,7 @@ static const struct of_device_id imx_rpmsg_dt_ids[] = {
        { .compatible = "fsl,imx7d-rpmsg",   .data = (void *)IMX7D, },
        { .compatible = "fsl,imx7ulp-rpmsg", .data = (void *)IMX7ULP, },
        { .compatible = "fsl,imx8qxp-rpmsg", .data = (void *)IMX8QXP, },
+       { .compatible = "fsl,imx8qm-rpmsg", .data = (void *)IMX8QM, },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, imx_rpmsg_dt_ids);
@@ -381,49 +372,53 @@ static void rpmsg_work_handler(struct work_struct *work)
 {
        u32 message;
        unsigned long flags;
+       struct delayed_work *dwork = to_delayed_work(work);
+       struct imx_rpmsg_vproc *rpdev = container_of(dwork,
+                       struct imx_rpmsg_vproc, rpmsg_work);
 
-       spin_lock_irqsave(&mu_lock, flags);
+       spin_lock_irqsave(&rpdev->mu_lock, flags);
        /* handle all incoming mu message */
-       while (in_idx != out_idx) {
-               message = m4_message[out_idx % MAX_NUM];
-               spin_unlock_irqrestore(&mu_lock, flags);
+       while (rpdev->in_idx != rpdev->out_idx) {
+               message = rpdev->m4_message[rpdev->out_idx % MAX_NUM];
+               spin_unlock_irqrestore(&rpdev->mu_lock, flags);
 
-               blocking_notifier_call_chain(&(mu_rpmsg_box.notifier), 4,
+               blocking_notifier_call_chain(&(rpdev->notifier), 4,
                                                (void *)(phys_addr_t)message);
 
-               spin_lock_irqsave(&mu_lock, flags);
-               m4_message[out_idx % MAX_NUM] = 0;
-               out_idx++;
+               spin_lock_irqsave(&rpdev->mu_lock, flags);
+               rpdev->m4_message[rpdev->out_idx % MAX_NUM] = 0;
+               rpdev->out_idx++;
        }
-       spin_unlock_irqrestore(&mu_lock, flags);
+       spin_unlock_irqrestore(&rpdev->mu_lock, flags);
 }
 
 static irqreturn_t imx_mu_rpmsg_isr(int irq, void *param)
 {
        u32 irqs, message;
        unsigned long flags;
+       struct imx_rpmsg_vproc *rpdev = (struct imx_rpmsg_vproc *)param;
 
-       irqs = MU_ReadStatus(mu_base);
+       irqs = MU_ReadStatus(rpdev->mu_base);
 
        /* RPMSG */
        if (irqs & (1 << 26)) {
-               spin_lock_irqsave(&mu_lock, flags);
+               spin_lock_irqsave(&rpdev->mu_lock, flags);
                /* get message from receive buffer */
-               MU_ReceiveMsg(mu_base, 1, &message);
-               m4_message[in_idx % MAX_NUM] = message;
-               in_idx++;
+               MU_ReceiveMsg(rpdev->mu_base, 1, &message);
+               rpdev->m4_message[rpdev->in_idx % MAX_NUM] = message;
+               rpdev->in_idx++;
                /*
                 * Too many mu message not be handled in timely, can enlarge
                 * MAX_NUM
                 */
-               if (in_idx == out_idx) {
-                       spin_unlock_irqrestore(&mu_lock, flags);
+               if (rpdev->in_idx == rpdev->out_idx) {
+                       spin_unlock_irqrestore(&rpdev->mu_lock, flags);
                        pr_err("MU overflow!\n");
                        return IRQ_HANDLED;
                }
-               spin_unlock_irqrestore(&mu_lock, flags);
+               spin_unlock_irqrestore(&rpdev->mu_lock, flags);
 
-               schedule_delayed_work(&rpmsg_work, 0);
+               schedule_delayed_work(&(rpdev->rpmsg_work), 0);
        }
 
        return IRQ_HANDLED;
@@ -431,21 +426,33 @@ static irqreturn_t imx_mu_rpmsg_isr(int irq, void *param)
 
 static int imx_rpmsg_probe(struct platform_device *pdev)
 {
-       int i, j, ret = 0;
+       int core_id, j, ret = 0;
        u32 irq;
        struct clk *clk;
        struct device_node *np_mu;
        struct device *dev = &pdev->dev;
        struct device_node *np = pdev->dev.of_node;
+       struct imx_rpmsg_vproc *rpdev;
 
        variant = (enum imx_rpmsg_variants)of_device_get_match_data(dev);
 
+       if (of_property_read_u32(np, "multi-core-id", &core_id))
+               core_id = 0;
+       rpdev = &imx_rpmsg_vprocs[core_id];
+       rpdev->core_id = core_id;
+
        /* Initialize the mu unit used by rpmsg */
-       np_mu = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-mu");
-       if (!np_mu)
+       if (rpdev->core_id == 1)
+               np_mu = of_find_compatible_node(NULL, NULL,
+                               "fsl,imx-mu-rpmsg1");
+       else
+               np_mu = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-mu");
+       if (!np_mu) {
                pr_info("Cannot find MU-RPMSG entry in device tree\n");
-       mu_base = of_iomap(np_mu, 0);
-       WARN_ON(!mu_base);
+               return -EINVAL;
+       }
+       rpdev->mu_base = of_iomap(np_mu, 0);
+       WARN_ON(!rpdev->mu_base);
 
        if (variant == IMX7ULP)
                irq = of_irq_get(np_mu, 1);
@@ -454,14 +461,14 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
 
        ret = request_irq(irq, imx_mu_rpmsg_isr,
                          IRQF_EARLY_RESUME | IRQF_SHARED,
-                         "imx-mu-rpmsg", dev);
+                         "imx-mu-rpmsg", rpdev);
        if (ret) {
                pr_err("%s: register interrupt %d failed, rc %d\n",
                        __func__, irq, ret);
                return ret;
        }
 
-       if (variant == IMX7D || variant == IMX8QXP) {
+       if (variant == IMX7D || variant == IMX8QXP || variant == IMX8QM) {
                clk = of_clk_get(np_mu, 0);
                if (IS_ERR(clk)) {
                        pr_err("mu clock source missing or invalid\n");
@@ -474,65 +481,60 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
                }
        }
 
-       INIT_DELAYED_WORK(&rpmsg_work, rpmsg_work_handler);
+       INIT_DELAYED_WORK(&(rpdev->rpmsg_work), rpmsg_work_handler);
        /*
         * bit26 is used by rpmsg channels.
         * bit0 of MX7ULP_MU_CR used to let m4 to know MU is ready now
         */
-       MU_Init(mu_base);
+       MU_Init(rpdev->mu_base);
        if (variant == IMX7ULP) {
-               MU_EnableRxFullInt(mu_base, 1);
-               MU_SetFn(mu_base, 1);
+               MU_EnableRxFullInt(rpdev->mu_base, 1);
+               MU_SetFn(rpdev->mu_base, 1);
        } else {
-               MU_EnableRxFullInt(mu_base, 1);
+               MU_EnableRxFullInt(rpdev->mu_base, 1);
        }
-       BLOCKING_INIT_NOTIFIER_HEAD(&(mu_rpmsg_box.notifier));
+       BLOCKING_INIT_NOTIFIER_HEAD(&(rpdev->notifier));
 
        pr_info("MU is ready for cross core communication!\n");
 
-       for (i = 0; i < ARRAY_SIZE(imx_rpmsg_vprocs); i++) {
-               struct imx_rpmsg_vproc *rpdev = &imx_rpmsg_vprocs[i];
+       ret = of_property_read_u32(np, "vdev-nums", &rpdev->vdev_nums);
+       if (ret)
+               rpdev->vdev_nums = 1;
+       if (rpdev->vdev_nums > MAX_VDEV_NUMS) {
+               pr_err("vdev-nums exceed the max %d\n", MAX_VDEV_NUMS);
+               return -EINVAL;
+       }
 
-               ret = of_property_read_u32_index(np, "vdev-nums", i,
-                       &rpdev->vdev_nums);
-               if (ret)
-                       rpdev->vdev_nums = 1;
-               if (rpdev->vdev_nums > MAX_VDEV_NUMS) {
-                       pr_err("vdev-nums exceed the max %d\n", MAX_VDEV_NUMS);
-                       return -EINVAL;
+       if (!strcmp(rpdev->rproc_name, "m4")) {
+               ret = set_vring_phy_buf(pdev, rpdev,
+                                       rpdev->vdev_nums);
+               if (ret) {
+                       pr_err("No vring buffer.\n");
+                       return -ENOMEM;
                }
+       } else {
+               pr_err("No remote m4 processor.\n");
+               return -ENODEV;
+       }
 
-               if (!strcmp(rpdev->rproc_name, "m4")) {
-                       ret = set_vring_phy_buf(pdev, rpdev,
-                                               rpdev->vdev_nums);
-                       if (ret) {
-                               pr_err("No vring buffer.\n");
-                               return -ENOMEM;
-                       }
-               } else {
-                       pr_err("No remote m4 processor.\n");
-                       return -ENODEV;
+       for (j = 0; j < rpdev->vdev_nums; j++) {
+               pr_debug("%s rpdev%d vdev%d: vring0 0x%x, vring1 0x%x\n",
+                        __func__, rpdev->core_id, rpdev->vdev_nums,
+                        rpdev->ivdev[j].vring[0],
+                        rpdev->ivdev[j].vring[1]);
+               rpdev->ivdev[j].vdev.id.device = VIRTIO_ID_RPMSG;
+               rpdev->ivdev[j].vdev.config = &imx_rpmsg_config_ops;
+               rpdev->ivdev[j].vdev.dev.parent = &pdev->dev;
+               rpdev->ivdev[j].vdev.dev.release = imx_rpmsg_vproc_release;
+               rpdev->ivdev[j].base_vq_id = j * 2;
+
+               ret = register_virtio_device(&rpdev->ivdev[j].vdev);
+               if (ret) {
+                       pr_err("%s failed to register rpdev: %d\n",
+                                       __func__, ret);
+                       return ret;
                }
 
-               for (j = 0; j < rpdev->vdev_nums; j++) {
-                       pr_debug("%s rpdev%d vdev%d: vring0 0x%x, vring1 0x%x\n",
-                                __func__, i, rpdev->vdev_nums,
-                                rpdev->ivdev[j].vring[0],
-                                rpdev->ivdev[j].vring[1]);
-                       rpdev->ivdev[j].vdev.id.device = VIRTIO_ID_RPMSG;
-                       rpdev->ivdev[j].vdev.config = &imx_rpmsg_config_ops;
-                       rpdev->ivdev[j].vdev.dev.parent = &pdev->dev;
-                       rpdev->ivdev[j].vdev.dev.release = imx_rpmsg_vproc_release;
-                       rpdev->ivdev[j].base_vq_id = j * 2;
-
-                       ret = register_virtio_device(&rpdev->ivdev[j].vdev);
-                       if (ret) {
-                               pr_err("%s failed to register rpdev: %d\n",
-                                               __func__, ret);
-                               return ret;
-                       }
-
-               }
        }
 
        return ret;
index aeaee17..3aa545f 100644 (file)
@@ -18,9 +18,7 @@
 #include <linux/rpmsg.h>
 
 #define MSG            "hello world!"
-#define MSG_LIMIT      51
 static unsigned int rpmsg_pingpong;
-static int rx_count;
 
 static int rpmsg_pingpong_cb(struct rpmsg_device *rpdev, void *data, int len,
                                                void *priv, u32 src)
@@ -29,12 +27,10 @@ static int rpmsg_pingpong_cb(struct rpmsg_device *rpdev, void *data, int len,
 
        /* reply */
        rpmsg_pingpong = *(unsigned int *)data;
-       pr_info("get %d (src: 0x%x)\n",
-                       rpmsg_pingpong, src);
-       rx_count++;
+       pr_info("get %d (src: 0x%x)\n", rpmsg_pingpong, src);
 
        /* pingpongs should not live forever */
-       if (rx_count >= MSG_LIMIT) {
+       if (rpmsg_pingpong > 100) {
                dev_info(&rpdev->dev, "goodbye!\n");
                return 0;
        }
@@ -65,7 +61,6 @@ static int rpmsg_pingpong_probe(struct rpmsg_device *rpdev)
        }
 
        rpmsg_pingpong = 0;
-       rx_count = 0;
        err = rpmsg_sendto(rpdev->ept, (void *)(&rpmsg_pingpong), 4, rpdev->dst);
        if (err) {
                dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", err);
@@ -82,6 +77,7 @@ static void rpmsg_pingpong_remove(struct rpmsg_device *rpdev)
 
 static struct rpmsg_device_id rpmsg_driver_pingpong_id_table[] = {
        { .name = "rpmsg-openamp-demo-channel" },
+       { .name = "rpmsg-openamp-demo-channel-1" },
        { },
 };
 MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_pingpong_id_table);
index 0cf531c..fadaa8f 100644 (file)
@@ -41,6 +41,4 @@ struct imx_rpmsg_head {
        u8 reserved[5];
 } __attribute__ ((packed));
 
-int imx_mu_rpmsg_register_nb(const char *name, struct notifier_block *nb);
-int imx_mu_rpmsg_unregister_nb(const char *name, struct notifier_block *nb);
 #endif /* __LINUX_IMX_RPMSG_H__ */