Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions Documentation/devicetree/bindings/arm/qcom,coresight-itnoc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/arm/qcom,coresight-itnoc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Qualcomm Interconnect Trace Network On Chip - ITNOC

maintainers:
- Yuanfang Zhang <yuanfang.zhang@oss.qualcomm.com>

description:
The Interconnect TNOC is a CoreSight graph link that forwards trace data
from a subsystem to the Aggregator TNOC. Compared to Aggregator TNOC, it
does not have aggregation and ATID functionality.

properties:
$nodename:
pattern: "^itnoc(@[0-9a-f]+)?$"

compatible:
const: qcom,coresight-itnoc

reg:
maxItems: 1

clocks:
maxItems: 1

clock-names:
items:
- const: apb

in-ports:
$ref: /schemas/graph.yaml#/properties/ports

patternProperties:
'^port(@[0-9a-f]{1,2})?$':
description: Input connections from CoreSight Trace Bus
$ref: /schemas/graph.yaml#/properties/port

out-ports:
$ref: /schemas/graph.yaml#/properties/ports
additionalProperties: false

properties:
port:
description: out connections to aggregator TNOC
$ref: /schemas/graph.yaml#/properties/port

required:
- compatible
- reg
- clocks
- clock-names
- in-ports
- out-ports

additionalProperties: false

examples:
- |
itnoc@109ac000 {
compatible = "qcom,coresight-itnoc";
reg = <0x109ac000 0x1000>;

clocks = <&aoss_qmp>;
clock-names = "apb";

in-ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
tn_ic_in_tpdm_dcc: endpoint {
remote-endpoint = <&tpdm_dcc_out_tn_ic>;
};
};
};

out-ports {
port {
tn_ic_out_tnoc_aggr: endpoint {
/* to Aggregator TNOC input */
remote-endpoint = <&tn_ag_in_tn_ic>;
};
};
};
};
...
16 changes: 2 additions & 14 deletions Documentation/devicetree/bindings/arm/qcom,coresight-tnoc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,12 @@ description: >

Note this binding is specifically intended for Aggregator TNOC instances.

# Need a custom select here or 'arm,primecell' will match on lots of nodes
select:
properties:
compatible:
contains:
enum:
- qcom,coresight-tnoc
required:
- compatible

properties:
$nodename:
pattern: "^tn(@[0-9a-f]+)$"

compatible:
items:
- const: qcom,coresight-tnoc
- const: arm,primecell
const: qcom,coresight-tnoc

reg:
maxItems: 1
Expand Down Expand Up @@ -83,7 +71,7 @@ additionalProperties: false
examples:
- |
tn@109ab000 {
compatible = "qcom,coresight-tnoc", "arm,primecell";
compatible = "qcom,coresight-tnoc";
reg = <0x109ab000 0x4200>;

clocks = <&aoss_qmp>;
Expand Down
139 changes: 128 additions & 11 deletions drivers/hwtracing/coresight/coresight-tnoc.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,17 @@
* @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.
*/
struct trace_noc_drvdata {
void __iomem *base;
struct device *dev;
struct coresight_device *csdev;
struct clk *pclk;
spinlock_t spinlock;
u32 atid;
int atid;
};

DEFINE_CORESIGHT_DEVLIST(trace_noc_devs, "traceNoc");
Expand All @@ -51,6 +53,12 @@ static void trace_noc_enable_hw(struct trace_noc_drvdata *drvdata)
{
u32 val;

/* No valid ATID, simply enable the unit */
if (drvdata->atid == -EOPNOTSUPP) {
writel(TRACE_NOC_CTRL_PORTEN, drvdata->base + TRACE_NOC_CTRL);
return;
}

/* Set ATID */
writel_relaxed(drvdata->atid, drvdata->base + TRACE_NOC_XLD);

Expand Down Expand Up @@ -125,6 +133,11 @@ static int trace_noc_init_default_data(struct trace_noc_drvdata *drvdata)
{
int atid;

if (of_device_is_compatible(drvdata->dev->of_node, "qcom,coresight-itnoc")) {
drvdata->atid = -EOPNOTSUPP;
return 0;
}

atid = coresight_trace_id_get_system_id();
if (atid < 0)
return atid;
Expand All @@ -150,18 +163,30 @@ static struct attribute *coresight_tnoc_attrs[] = {
NULL,
};

static umode_t trace_id_is_visible(struct kobject *kobj,
struct attribute *attr, int idx)
{
struct device *dev = kobj_to_dev(kobj);
struct trace_noc_drvdata *drvdata = dev_get_drvdata(dev->parent);

if (attr == &dev_attr_traceid.attr && drvdata->atid < 0)
return 0;

return attr->mode;
}

static const struct attribute_group coresight_tnoc_group = {
.attrs = coresight_tnoc_attrs,
.is_visible = trace_id_is_visible,
};

static const struct attribute_group *coresight_tnoc_groups[] = {
&coresight_tnoc_group,
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)
{
struct device *dev = &adev->dev;
struct coresight_platform_data *pdata;
struct trace_noc_drvdata *drvdata;
struct coresight_desc desc = { 0 };
Expand All @@ -174,16 +199,20 @@ 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);

Expand All @@ -196,20 +225,31 @@ static int trace_noc_probe(struct amba_device *adev, const struct amba_id *id)
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;
drvdata->csdev = coresight_register(&desc);
if (IS_ERR(drvdata->csdev)) {
coresight_trace_id_put_system_id(drvdata->atid);
if (drvdata->atid > 0)
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);
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);
Expand Down Expand Up @@ -241,7 +281,84 @@ static struct amba_driver trace_noc_driver = {
.id_table = trace_noc_ids,
};

module_amba_driver(trace_noc_driver);
static int tnoc_platform_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);
pm_runtime_put(&pdev->dev);
if (ret)
pm_runtime_disable(&pdev->dev);

return ret;
}

static void tnoc_platform_remove(struct platform_device *pdev)
{
struct trace_noc_drvdata *drvdata = platform_get_drvdata(pdev);

coresight_unregister(drvdata->csdev);
pm_runtime_disable(&pdev->dev);
if (drvdata->atid > 0)
coresight_trace_id_put_system_id(drvdata->atid);
}

#ifdef CONFIG_PM
static int tnoc_runtime_suspend(struct device *dev)
{
struct trace_noc_drvdata *drvdata = dev_get_drvdata(dev);

clk_disable_unprepare(drvdata->pclk);

return 0;
}

static int tnoc_runtime_resume(struct device *dev)
{
struct trace_noc_drvdata *drvdata = dev_get_drvdata(dev);

return clk_prepare_enable(drvdata->pclk);
}
#endif

static const struct dev_pm_ops tnoc_dev_pm_ops = {
SET_RUNTIME_PM_OPS(tnoc_runtime_suspend, tnoc_runtime_resume, NULL)
};

static const struct of_device_id tnoc_of_match[] = {
{ .compatible = "qcom,coresight-itnoc" },
{ .compatible = "qcom,coresight-tnoc" },
{}
};
MODULE_DEVICE_TABLE(of, tnoc_of_match);

static struct platform_driver tnoc_platform_driver = {
.probe = tnoc_platform_probe,
.remove = tnoc_platform_remove,
.driver = {
.name = "coresight-tnoc",
.of_match_table = tnoc_of_match,
.suppress_bind_attrs = true,
.pm = &tnoc_dev_pm_ops,
},
};

static int __init tnoc_init(void)
{
return coresight_init_driver("tnoc", &trace_noc_driver, &tnoc_platform_driver, THIS_MODULE);
}

static void __exit tnoc_exit(void)
{
coresight_remove_driver(&trace_noc_driver, &tnoc_platform_driver);
}
module_init(tnoc_init);
module_exit(tnoc_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Trace NOC driver");
Loading