This patch adds platform driver support for the CoreSight Interconnect TNOC, Interconnect TNOC is a CoreSight link that forwards trace data from a subsystem to the Aggregator TNOC. Compared to Aggregator TNOC, it does not have aggregation and ATID functionality.
Key changes: - Add platform driver `coresight-itnoc` with device tree match support. - Refactor probe logic into a common `_tnoc_probe()` function. - Conditionally initialize ATID only for AMBA-based TNOC blocks.
Signed-off-by: Yuanfang Zhang yuanfang.zhang@oss.qualcomm.com --- drivers/hwtracing/coresight/coresight-tnoc.c | 153 +++++++++++++++++++-------- 1 file changed, 106 insertions(+), 47 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-tnoc.c b/drivers/hwtracing/coresight/coresight-tnoc.c index d542df46ea39314605290311f683010337bfd4bd..aa6f48d838c00d71eff22c18e34e00b93755fd82 100644 --- a/drivers/hwtracing/coresight/coresight-tnoc.c +++ b/drivers/hwtracing/coresight/coresight-tnoc.c @@ -34,6 +34,7 @@ * @base: memory mapped base address for this component. * @dev: device node for trace_noc_drvdata. * @csdev: component vitals needed by the framework. + * @pclk: APB clock if present, otherwise NULL * @spinlock: serialize enable/disable operation. * @atid: id for the trace packet. */ @@ -41,6 +42,7 @@ struct trace_noc_drvdata { void __iomem *base; struct device *dev; struct coresight_device *csdev; + struct clk *pclk; spinlock_t spinlock; u32 atid; }; @@ -51,25 +53,27 @@ static void trace_noc_enable_hw(struct trace_noc_drvdata *drvdata) { u32 val;
- /* Set ATID */ - writel_relaxed(drvdata->atid, drvdata->base + TRACE_NOC_XLD); - - /* Set the data word count between 'SYNC' packets */ - writel_relaxed(TRACE_NOC_SYNC_INTERVAL, drvdata->base + TRACE_NOC_SYNCR); - - /* Set the Control register: - * - Set the FLAG packets to 'FLAG' packets - * - Set the FREQ packets to 'FREQ_TS' packets - * - Enable generation of output ATB traffic - */ - - val = readl_relaxed(drvdata->base + TRACE_NOC_CTRL); - - val &= ~TRACE_NOC_CTRL_FLAGTYPE; - val |= TRACE_NOC_CTRL_FREQTYPE; - val |= TRACE_NOC_CTRL_PORTEN; - - writel(val, drvdata->base + TRACE_NOC_CTRL); + if (drvdata->atid) { + /* Set ATID */ + writel_relaxed(drvdata->atid, drvdata->base + TRACE_NOC_XLD); + + /* Set the data word count between 'SYNC' packets */ + writel_relaxed(TRACE_NOC_SYNC_INTERVAL, drvdata->base + TRACE_NOC_SYNCR); + /* Set the Control register: + * - Set the FLAG packets to 'FLAG' packets + * - Set the FREQ packets to 'FREQ_TS' packets + * - Enable generation of output ATB traffic + */ + + val = readl_relaxed(drvdata->base + TRACE_NOC_CTRL); + + val &= ~TRACE_NOC_CTRL_FLAGTYPE; + val |= TRACE_NOC_CTRL_FREQTYPE; + val |= TRACE_NOC_CTRL_PORTEN; + writel(val, drvdata->base + TRACE_NOC_CTRL); + } else { + writel(0x1, drvdata->base + TRACE_NOC_CTRL); + } }
static int trace_noc_enable(struct coresight_device *csdev, struct coresight_connection *inport, @@ -120,19 +124,6 @@ static const struct coresight_ops trace_noc_cs_ops = { .link_ops = &trace_noc_link_ops, };
-static int trace_noc_init_default_data(struct trace_noc_drvdata *drvdata) -{ - int atid; - - atid = coresight_trace_id_get_system_id(); - if (atid < 0) - return atid; - - drvdata->atid = atid; - - return 0; -} - static ssize_t traceid_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -158,13 +149,12 @@ static const struct attribute_group *coresight_tnoc_groups[] = { NULL, };
-static int trace_noc_probe(struct amba_device *adev, const struct amba_id *id) +static int _tnoc_probe(struct device *dev, struct resource *res, bool has_id) { - struct device *dev = &adev->dev; struct coresight_platform_data *pdata; struct trace_noc_drvdata *drvdata; struct coresight_desc desc = { 0 }; - int ret; + int ret, atid = 0;
desc.name = coresight_alloc_device_name(&trace_noc_devs, dev); if (!desc.name) @@ -173,42 +163,61 @@ static int trace_noc_probe(struct amba_device *adev, const struct amba_id *id) pdata = coresight_get_platform_data(dev); if (IS_ERR(pdata)) return PTR_ERR(pdata); - adev->dev.platform_data = pdata; + dev->platform_data = pdata;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) return -ENOMEM;
- drvdata->dev = &adev->dev; + drvdata->dev = dev; dev_set_drvdata(dev, drvdata);
- drvdata->base = devm_ioremap_resource(dev, &adev->res); + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, NULL); + if (ret) + return ret; + + drvdata->base = devm_ioremap_resource(dev, res); if (IS_ERR(drvdata->base)) return PTR_ERR(drvdata->base);
spin_lock_init(&drvdata->spinlock);
- ret = trace_noc_init_default_data(drvdata); - if (ret) - return ret; + if (has_id) { + atid = coresight_trace_id_get_system_id(); + if (atid < 0) + return atid; + } + + drvdata->atid = atid;
desc.ops = &trace_noc_cs_ops; desc.type = CORESIGHT_DEV_TYPE_LINK; desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG; - desc.pdata = adev->dev.platform_data; - desc.dev = &adev->dev; + desc.pdata = pdata; + desc.dev = dev; desc.access = CSDEV_ACCESS_IOMEM(drvdata->base); - desc.groups = coresight_tnoc_groups; + if (has_id) + desc.groups = coresight_tnoc_groups; drvdata->csdev = coresight_register(&desc); - if (IS_ERR(drvdata->csdev)) { + if (IS_ERR(drvdata->csdev) && has_id) { coresight_trace_id_put_system_id(drvdata->atid); return PTR_ERR(drvdata->csdev); } - pm_runtime_put(&adev->dev);
return 0; }
+static int trace_noc_probe(struct amba_device *adev, const struct amba_id *id) +{ + int ret; + + ret = _tnoc_probe(&adev->dev, &adev->res, true); + if (!ret) + pm_runtime_put(&adev->dev); + + return ret; +} + static void trace_noc_remove(struct amba_device *adev) { struct trace_noc_drvdata *drvdata = dev_get_drvdata(&adev->dev); @@ -236,7 +245,57 @@ static struct amba_driver trace_noc_driver = { .id_table = trace_noc_ids, };
-module_amba_driver(trace_noc_driver); +static int itnoc_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int ret; + + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + ret = _tnoc_probe(&pdev->dev, res, false); + pm_runtime_put(&pdev->dev); + if (ret) + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static void itnoc_remove(struct platform_device *pdev) +{ + struct trace_noc_drvdata *drvdata = platform_get_drvdata(pdev); + + coresight_unregister(drvdata->csdev); + pm_runtime_disable(&pdev->dev); +} + +static const struct of_device_id itnoc_of_match[] = { + { .compatible = "qcom,coresight-itnoc" }, + {} +}; +MODULE_DEVICE_TABLE(of, itnoc_of_match); + +static struct platform_driver itnoc_driver = { + .probe = itnoc_probe, + .remove = itnoc_remove, + .driver = { + .name = "coresight-itnoc", + .of_match_table = itnoc_of_match, + }, +}; + +static int __init tnoc_init(void) +{ + return coresight_init_driver("tnoc", &trace_noc_driver, &itnoc_driver, THIS_MODULE); +} + +static void __exit tnoc_exit(void) +{ + coresight_remove_driver(&trace_noc_driver, &itnoc_driver); +} +module_init(tnoc_init); +module_exit(tnoc_exit);
MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Trace NOC driver");