The DSP could be debugged using JTAG.
The support of JTAG could enabled at build time and it could be enabled
using debugfs.

Signed-off-by: Alexandre Bailon <abai...@baylibre.com>
---
 drivers/remoteproc/Kconfig   |   9 +++
 drivers/remoteproc/mtk_apu.c | 151 ++++++++++++++++++++++++++++++++++-
 2 files changed, 159 insertions(+), 1 deletion(-)

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 4ebea57bf4c8..310462346bd8 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -61,6 +61,15 @@ config MTK_APU
 
          It's safe to say N here.
 
+config MTK_APU_JTAG
+       bool "Enable support of JTAG"
+       depends on MTK_APU
+       help
+         Say y to enable support of JTAG.
+         By default, JTAG will remain disabled until it is enabled using
+         debugfs: remoteproc/remoteproc0/jtag. Write 1 to enable it and
+         0 to disable it.
+
 config OMAP_REMOTEPROC
        tristate "OMAP remoteproc support"
        depends on ARCH_OMAP4 || SOC_OMAP5 || SOC_DRA7XX
diff --git a/drivers/remoteproc/mtk_apu.c b/drivers/remoteproc/mtk_apu.c
index 6d2f577cfde5..07157fdc24ba 100644
--- a/drivers/remoteproc/mtk_apu.c
+++ b/drivers/remoteproc/mtk_apu.c
@@ -5,6 +5,7 @@
 
 #include <linux/bitops.h>
 #include <linux/clk.h>
+#include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/highmem.h>
 #include <linux/interrupt.h>
@@ -14,6 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of_reserved_mem.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/remoteproc.h>
 
@@ -48,6 +50,11 @@
 #define CORE_DEFAULT1                          (0x00000140)
 #define CORE_DEFAULT0_ARUSER_IDMA_USE_IOMMU    (0x10 << 0)
 #define CORE_DEFAULT0_AWUSER_IDMA_USE_IOMMU    (0x10 << 5)
+#define CORE_DEFAULT2                          (0x00000144)
+#define CORE_DEFAULT2_DBG_EN                   BIT(3)
+#define CORE_DEFAULT2_NIDEN                    BIT(2)
+#define CORE_DEFAULT2_SPNIDEN                  BIT(1)
+#define CORE_DEFAULT2_SPIDEN                   BIT(0)
 #define CORE_XTENSA_ALTRESETVEC                        (0x000001F8)
 
 struct mtk_apu_rproc {
@@ -57,6 +64,13 @@ struct mtk_apu_rproc {
        void __iomem *base;
        int irq;
        struct clk_bulk_data clks[3];
+
+#ifdef CONFIG_MTK_APU_JTAG
+       struct pinctrl *pinctrl;
+       struct pinctrl_state *pinctrl_jtag;
+       bool jtag_enabled;
+       struct mutex jtag_mutex;
+#endif
 };
 
 static int mtk_apu_rproc_prepare(struct rproc *rproc)
@@ -166,6 +180,137 @@ static irqreturn_t handle_event(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_MTK_APU_JTAG
+
+static int apu_enable_jtag(struct mtk_apu_rproc *apu_rproc)
+{
+       int ret = 0;
+
+       mutex_lock(&apu_rproc->jtag_mutex);
+       if (apu_rproc->jtag_enabled) {
+               ret = -EINVAL;
+               goto err_mutex_unlock;
+       }
+
+       writel(CORE_DEFAULT2_SPNIDEN | CORE_DEFAULT2_SPIDEN |
+               CORE_DEFAULT2_NIDEN | CORE_DEFAULT2_DBG_EN,
+               apu_rproc->base + CORE_DEFAULT2);
+
+       apu_rproc->jtag_enabled = 1;
+
+err_mutex_unlock:
+       mutex_unlock(&apu_rproc->jtag_mutex);
+
+       return ret;
+}
+
+static int apu_disable_jtag(struct mtk_apu_rproc *apu_rproc)
+{
+       int ret = 0;
+
+       mutex_lock(&apu_rproc->jtag_mutex);
+       if (!apu_rproc->jtag_enabled) {
+               ret = -EINVAL;
+               goto err_mutex_unlock;
+       }
+
+       writel(0, apu_rproc->base + CORE_DEFAULT2);
+
+       apu_rproc->jtag_enabled = 0;
+
+err_mutex_unlock:
+       mutex_unlock(&apu_rproc->jtag_mutex);
+
+       return ret;
+}
+
+static ssize_t rproc_jtag_read(struct file *filp, char __user *userbuf,
+                              size_t count, loff_t *ppos)
+{
+       struct rproc *rproc = filp->private_data;
+       struct mtk_apu_rproc *apu_rproc = (struct mtk_apu_rproc *)rproc->priv;
+       char *buf = apu_rproc->jtag_enabled ? "enabled\n" : "disabled\n";
+
+       return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
+}
+
+static ssize_t rproc_jtag_write(struct file *filp, const char __user *user_buf,
+                               size_t count, loff_t *ppos)
+{
+       struct rproc *rproc = filp->private_data;
+       struct mtk_apu_rproc *apu_rproc = (struct mtk_apu_rproc *)rproc->priv;
+       char buf[10];
+       int ret;
+
+       if (count < 1 || count > sizeof(buf))
+               return -EINVAL;
+
+       ret = copy_from_user(buf, user_buf, count);
+       if (ret)
+               return -EFAULT;
+
+       /* remove end of line */
+       if (buf[count - 1] == '\n')
+               buf[count - 1] = '\0';
+
+       if (!strncmp(buf, "enabled", count))
+               ret = apu_enable_jtag(apu_rproc);
+       else if (!strncmp(buf, "disabled", count))
+               ret = apu_disable_jtag(apu_rproc);
+       else
+               return -EINVAL;
+
+       return ret ? ret : count;
+}
+
+static const struct file_operations rproc_jtag_ops = {
+       .read = rproc_jtag_read,
+       .write = rproc_jtag_write,
+       .open = simple_open,
+};
+
+static int apu_jtag_probe(struct mtk_apu_rproc *apu_rproc)
+{
+       int ret;
+
+       if (!apu_rproc->rproc->dbg_dir)
+               return -ENODEV;
+
+       apu_rproc->pinctrl = devm_pinctrl_get(apu_rproc->dev);
+       if (IS_ERR(apu_rproc->pinctrl)) {
+               dev_warn(apu_rproc->dev, "Failed to find JTAG pinctrl\n");
+               return PTR_ERR(apu_rproc->pinctrl);
+       }
+
+       apu_rproc->pinctrl_jtag = pinctrl_lookup_state(apu_rproc->pinctrl,
+                                                      "jtag");
+       if (IS_ERR(apu_rproc->pinctrl_jtag))
+               return PTR_ERR(apu_rproc->pinctrl_jtag);
+
+       ret = pinctrl_select_state(apu_rproc->pinctrl,
+                                  apu_rproc->pinctrl_jtag);
+       if (ret < 0)
+               return ret;
+
+       mutex_init(&apu_rproc->jtag_mutex);
+
+       debugfs_create_file("jtag", 0600, apu_rproc->rproc->dbg_dir,
+                           apu_rproc->rproc, &rproc_jtag_ops);
+
+       return 0;
+}
+#else
+static int apu_jtag_probe(struct mtk_apu_rproc *apu_rproc)
+{
+       return 0;
+}
+
+static int apu_disable_jtag(struct mtk_apu_rproc *apu_rproc)
+{
+       return 0;
+}
+#endif /* CONFIG_MTK_APU_JTAG */
+
 static int mtk_apu_rproc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -242,6 +387,10 @@ static int mtk_apu_rproc_probe(struct platform_device 
*pdev)
                goto free_mem;
        }
 
+       ret = apu_jtag_probe(apu_rproc);
+       if (ret)
+               dev_warn(dev, "Failed to configure jtag\n");
+
        return 0;
 
 free_mem:
@@ -259,7 +408,7 @@ static int mtk_apu_rproc_remove(struct platform_device 
*pdev)
        struct device *dev = &pdev->dev;
 
        disable_irq(apu_rproc->irq);
-
+       apu_disable_jtag(apu_rproc);
        rproc_del(rproc);
        of_reserved_mem_device_release(dev);
        rproc_free(rproc);
-- 
2.26.2

Reply via email to