Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit efc21932 authored by Leo Yan's avatar Leo Yan Committed by Yabin Cui
Browse files

BACKPORT: coresight: funnel: Support static funnel



Backport: manual fix in funnel_enable/disable because later patches have
been backported before it.

Since CoreSight hardware topology can use a 'hidden' funnel in the
trace data path, this kind funnel doesn't have register for accessing
and is used by default from hardware design perspective.  Below is an
example for related hardware topology:

  +------+  +------+
  | cpu0 |->| ETM  |-\
  +------+  +------+  \-> +--------+  +-----+
   ......                 | Funnel |->| ETF |-\    Hidden funnel
  +------+  +------+  /-> +--------+  +-----+  \        |
  | cpu3 |->| ETM  |-/                          \       V
  +------+  +------+                             \-> +--------+
                                                     | Funnel |-> ...
  +------+  +------+                             /-> +--------+
  | cpu4 |->| ETM  |-\                          /
  +------+  +------+  \-> +--------+  +-----+  /
   ......                 | Funnel |->| ETF |-/
  +------+  +------+  /-> +--------+  +-----+
  | cpu7 |->| ETM  |-/
  +------+  +------+

The CoreSight funnel driver only supports dynamic funnel with
registration register resource, thus it cannot support for the static
funnel case and it's impossible to create trace data path for this case.

This patch is to extend CoreSight funnel driver to support both for
static funnel and dynamic funnel.  For the dynamic funnel it reuses the
code existed in the driver, for static funnel the driver will support
device probe if without providing register resource and the driver skips
registers accessing when detect the register base is NULL.

Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: Wanglai Shi <shiwanglai@hisilicon.com>
Suggested-by: default avatarSuzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: default avatarLeo Yan <leo.yan@linaro.org>
Reviewed-by: default avatarSuzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: default avatarMathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>

(Upstream commit 78e6427b4e7b017951785982f7f97cf64e2d624b).

Bug: 140266694
Change-Id: I9bb1b61d37d729dece8a5d3a66c5d1db1a3b5863
Signed-off-by: default avatarYabin Cui <yabinc@google.com>
parent 8118759d
Loading
Loading
Loading
Loading
+89 −27
Original line number Diff line number Diff line
@@ -12,6 +12,8 @@
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/coresight.h>
#include <linux/amba/bus.h>
@@ -45,7 +47,7 @@ struct funnel_drvdata {
	spinlock_t		spinlock;
};

static int funnel_enable_hw(struct funnel_drvdata *drvdata, int port)
static int dynamic_funnel_enable_hw(struct funnel_drvdata *drvdata, int port)
{
	u32 functl;
	int rc = 0;
@@ -73,14 +75,15 @@ static int funnel_enable_hw(struct funnel_drvdata *drvdata, int port)
static int funnel_enable(struct coresight_device *csdev, int inport,
			 int outport)
{
	int rc;
	int rc = 0;
	struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
	unsigned long flags;
	bool first_enable = false;

	spin_lock_irqsave(&drvdata->spinlock, flags);
	if (atomic_read(&csdev->refcnt[inport]) == 0) {
		rc = funnel_enable_hw(drvdata, inport);
		if (drvdata->base)
			rc = dynamic_funnel_enable_hw(drvdata, inport);
		if (!rc)
			first_enable = true;
	}
@@ -93,7 +96,8 @@ static int funnel_enable(struct coresight_device *csdev, int inport,
	return rc;
}

static void funnel_disable_hw(struct funnel_drvdata *drvdata, int inport)
static void dynamic_funnel_disable_hw(struct funnel_drvdata *drvdata,
				      int inport)
{
	u32 functl;

@@ -119,7 +123,8 @@ static void funnel_disable(struct coresight_device *csdev, int inport,

	spin_lock_irqsave(&drvdata->spinlock, flags);
	if (atomic_dec_return(&csdev->refcnt[inport]) == 0) {
		funnel_disable_hw(drvdata, inport);
		if (drvdata->base)
			dynamic_funnel_disable_hw(drvdata, inport);
		last_disable = true;
	}
	spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -197,44 +202,52 @@ static struct attribute *coresight_funnel_attrs[] = {
};
ATTRIBUTE_GROUPS(coresight_funnel);

static int funnel_probe(struct amba_device *adev, const struct amba_id *id)
static int funnel_probe(struct device *dev, struct resource *res)
{
	int ret;
	void __iomem *base;
	struct device *dev = &adev->dev;
	struct coresight_platform_data *pdata = NULL;
	struct funnel_drvdata *drvdata;
	struct resource *res = &adev->res;
	struct coresight_desc desc = { 0 };
	struct device_node *np = adev->dev.of_node;
	struct device_node *np = dev->of_node;

	if (np) {
		pdata = of_get_coresight_platform_data(dev, np);
		if (IS_ERR(pdata))
			return PTR_ERR(pdata);
		adev->dev.platform_data = pdata;
		dev->platform_data = pdata;
	}

	if (of_device_is_compatible(np, "arm,coresight-funnel"))
		pr_warn_once("Uses OBSOLETE CoreSight funnel binding\n");

	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
	if (!drvdata)
		return -ENOMEM;

	drvdata->dev = &adev->dev;
	drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
	drvdata->dev = dev;
	drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */
	if (!IS_ERR(drvdata->atclk)) {
		ret = clk_prepare_enable(drvdata->atclk);
		if (ret)
			return ret;
	}
	dev_set_drvdata(dev, drvdata);

	/* Validity for the resource is already checked by the AMBA core */
	/*
	 * Map the device base for dynamic-funnel, which has been
	 * validated by AMBA core.
	 */
	if (res) {
		base = devm_ioremap_resource(dev, res);
	if (IS_ERR(base))
		return PTR_ERR(base);

		if (IS_ERR(base)) {
			ret = PTR_ERR(base);
			goto out_disable_clk;
		}
		drvdata->base = base;
	pm_runtime_put(&adev->dev);
		desc.groups = coresight_funnel_groups;
	}

	dev_set_drvdata(dev, drvdata);

	spin_lock_init(&drvdata->spinlock);
	desc.type = CORESIGHT_DEV_TYPE_LINK;
@@ -242,10 +255,18 @@ static int funnel_probe(struct amba_device *adev, const struct amba_id *id)
	desc.ops = &funnel_cs_ops;
	desc.pdata = pdata;
	desc.dev = dev;
	desc.groups = coresight_funnel_groups;
	drvdata->csdev = coresight_register(&desc);
	if (IS_ERR(drvdata->csdev)) {
		ret = PTR_ERR(drvdata->csdev);
		goto out_disable_clk;
	}

	pm_runtime_put(dev);

	return PTR_ERR_OR_ZERO(drvdata->csdev);
out_disable_clk:
	if (ret && !IS_ERR_OR_NULL(drvdata->atclk))
		clk_disable_unprepare(drvdata->atclk);
	return ret;
}

#ifdef CONFIG_PM
@@ -274,7 +295,48 @@ static const struct dev_pm_ops funnel_dev_pm_ops = {
	SET_RUNTIME_PM_OPS(funnel_runtime_suspend, funnel_runtime_resume, NULL)
};

static const struct amba_id funnel_ids[] = {
static int static_funnel_probe(struct platform_device *pdev)
{
	int ret;

	pm_runtime_get_noresume(&pdev->dev);
	pm_runtime_set_active(&pdev->dev);
	pm_runtime_enable(&pdev->dev);

	/* Static funnel do not have programming base */
	ret = funnel_probe(&pdev->dev, NULL);

	if (ret) {
		pm_runtime_put_noidle(&pdev->dev);
		pm_runtime_disable(&pdev->dev);
	}

	return ret;
}

static const struct of_device_id static_funnel_match[] = {
	{.compatible = "arm,coresight-static-funnel"},
	{}
};

static struct platform_driver static_funnel_driver = {
	.probe          = static_funnel_probe,
	.driver         = {
		.name   = "coresight-static-funnel",
		.of_match_table = static_funnel_match,
		.pm	= &funnel_dev_pm_ops,
		.suppress_bind_attrs = true,
	},
};
builtin_platform_driver(static_funnel_driver);

static int dynamic_funnel_probe(struct amba_device *adev,
				const struct amba_id *id)
{
	return funnel_probe(&adev->dev, &adev->res);
}

static const struct amba_id dynamic_funnel_ids[] = {
	{
		.id     = 0x000bb908,
		.mask   = 0x000fffff,
@@ -287,14 +349,14 @@ static const struct amba_id funnel_ids[] = {
	{ 0, 0},
};

static struct amba_driver funnel_driver = {
static struct amba_driver dynamic_funnel_driver = {
	.drv = {
		.name	= "coresight-funnel",
		.name	= "coresight-dynamic-funnel",
		.owner	= THIS_MODULE,
		.pm	= &funnel_dev_pm_ops,
		.suppress_bind_attrs = true,
	},
	.probe		= funnel_probe,
	.id_table	= funnel_ids,
	.probe		= dynamic_funnel_probe,
	.id_table	= dynamic_funnel_ids,
};
builtin_amba_driver(funnel_driver);
builtin_amba_driver(dynamic_funnel_driver);