Commit 5ecc7120 authored by Suzuki K Poulose's avatar Suzuki K Poulose Committed by Greg Kroah-Hartman

coresight: Cleanup coresight DT bindings

The coresight drivers relied on default bindings for graph
in DT, while reusing the "reg" field of the "ports" to indicate
the actual hardware port number for the connections. This can
cause duplicate ports with same addresses, but different
direction. However, with the rules getting stricter for the
address mismatch with the label, it is no longer possible to use
the port address field for the hardware port number.

This patch introduces new DT binding rules for coresight
components, based on the same generic DT graph bindings, but
avoiding the address duplication.

- All output ports must be specified under a child node with
  name "out-ports".
- All input ports must be specified under a childe node with
  name "in-ports".
- Port address should match the hardware port number.

The support for legacy bindings is retained, with a warning.

Cc: Sudeep Holla <sudeep.holla@arm.com>
Cc: Rob Herring <robh@kernel.org>
Signed-off-by: default avatarSuzuki K Poulose <suzuki.poulose@arm.com>
Reviewed-by: default avatarRob Herring <robh@kernel.org>
Signed-off-by: default avatarMathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c2c72941
...@@ -54,9 +54,7 @@ its hardware characteristcs. ...@@ -54,9 +54,7 @@ its hardware characteristcs.
clocks the core of that coresight component. The latter clock clocks the core of that coresight component. The latter clock
is optional. is optional.
* port or ports: The representation of the component's port * port or ports: see "Graph bindings for Coresight" below.
layout using the generic DT graph presentation found in
"bindings/graph.txt".
* Additional required properties for System Trace Macrocells (STM): * Additional required properties for System Trace Macrocells (STM):
* reg: along with the physical base address and length of the register * reg: along with the physical base address and length of the register
...@@ -73,7 +71,7 @@ its hardware characteristcs. ...@@ -73,7 +71,7 @@ its hardware characteristcs.
AMBA markee): AMBA markee):
- "arm,coresight-replicator" - "arm,coresight-replicator"
* port or ports: same as above. * port or ports: see "Graph bindings for Coresight" below.
* Optional properties for ETM/PTMs: * Optional properties for ETM/PTMs:
...@@ -96,6 +94,20 @@ its hardware characteristcs. ...@@ -96,6 +94,20 @@ its hardware characteristcs.
* interrupts : Exactly one SPI may be listed for reporting the address * interrupts : Exactly one SPI may be listed for reporting the address
error error
Graph bindings for Coresight
-------------------------------
Coresight components are interconnected to create a data path for the flow of
trace data generated from the "sources" to their collection points "sink".
Each coresight component must describe the "input" and "output" connections.
The connections must be described via generic DT graph bindings as described
by the "bindings/graph.txt", where each "port" along with an "endpoint"
component represents a hardware port and the connection.
* All output ports must be listed inside a child node named "out-ports"
* All input ports must be listed inside a child node named "in-ports".
* Port address must match the hardware port number.
Example: Example:
1. Sinks 1. Sinks
...@@ -105,13 +117,14 @@ Example: ...@@ -105,13 +117,14 @@ Example:
clocks = <&oscclk6a>; clocks = <&oscclk6a>;
clock-names = "apb_pclk"; clock-names = "apb_pclk";
in-ports {
port { port {
etb_in_port: endpoint@0 { etb_in_port: endpoint@0 {
slave-mode;
remote-endpoint = <&replicator_out_port0>; remote-endpoint = <&replicator_out_port0>;
}; };
}; };
}; };
};
tpiu@20030000 { tpiu@20030000 {
compatible = "arm,coresight-tpiu", "arm,primecell"; compatible = "arm,coresight-tpiu", "arm,primecell";
...@@ -119,13 +132,14 @@ Example: ...@@ -119,13 +132,14 @@ Example:
clocks = <&oscclk6a>; clocks = <&oscclk6a>;
clock-names = "apb_pclk"; clock-names = "apb_pclk";
out-ports {
port { port {
tpiu_in_port: endpoint@0 { tpiu_in_port: endpoint@0 {
slave-mode;
remote-endpoint = <&replicator_out_port1>; remote-endpoint = <&replicator_out_port1>;
}; };
}; };
}; };
};
etr@20070000 { etr@20070000 {
compatible = "arm,coresight-tmc", "arm,primecell"; compatible = "arm,coresight-tmc", "arm,primecell";
...@@ -163,7 +177,7 @@ Example: ...@@ -163,7 +177,7 @@ Example:
*/ */
compatible = "arm,coresight-replicator"; compatible = "arm,coresight-replicator";
ports { out-ports {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
...@@ -181,12 +195,11 @@ Example: ...@@ -181,12 +195,11 @@ Example:
remote-endpoint = <&tpiu_in_port>; remote-endpoint = <&tpiu_in_port>;
}; };
}; };
};
/* replicator input port */ in-ports {
port@2 { port {
reg = <0>;
replicator_in_port0: endpoint { replicator_in_port0: endpoint {
slave-mode;
remote-endpoint = <&funnel_out_port0>; remote-endpoint = <&funnel_out_port0>;
}; };
}; };
...@@ -199,40 +212,36 @@ Example: ...@@ -199,40 +212,36 @@ Example:
clocks = <&oscclk6a>; clocks = <&oscclk6a>;
clock-names = "apb_pclk"; clock-names = "apb_pclk";
ports { out-ports {
#address-cells = <1>; port {
#size-cells = <0>;
/* funnel output port */
port@0 {
reg = <0>;
funnel_out_port0: endpoint { funnel_out_port0: endpoint {
remote-endpoint = remote-endpoint =
<&replicator_in_port0>; <&replicator_in_port0>;
}; };
}; };
};
/* funnel input ports */ in-ports {
port@1 { #address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>; reg = <0>;
funnel_in_port0: endpoint { funnel_in_port0: endpoint {
slave-mode;
remote-endpoint = <&ptm0_out_port>; remote-endpoint = <&ptm0_out_port>;
}; };
}; };
port@2 { port@1 {
reg = <1>; reg = <1>;
funnel_in_port1: endpoint { funnel_in_port1: endpoint {
slave-mode;
remote-endpoint = <&ptm1_out_port>; remote-endpoint = <&ptm1_out_port>;
}; };
}; };
port@3 { port@2 {
reg = <2>; reg = <2>;
funnel_in_port2: endpoint { funnel_in_port2: endpoint {
slave-mode;
remote-endpoint = <&etm0_out_port>; remote-endpoint = <&etm0_out_port>;
}; };
}; };
...@@ -248,12 +257,14 @@ Example: ...@@ -248,12 +257,14 @@ Example:
cpu = <&cpu0>; cpu = <&cpu0>;
clocks = <&oscclk6a>; clocks = <&oscclk6a>;
clock-names = "apb_pclk"; clock-names = "apb_pclk";
out-ports {
port { port {
ptm0_out_port: endpoint { ptm0_out_port: endpoint {
remote-endpoint = <&funnel_in_port0>; remote-endpoint = <&funnel_in_port0>;
}; };
}; };
}; };
};
ptm@2201d000 { ptm@2201d000 {
compatible = "arm,coresight-etm3x", "arm,primecell"; compatible = "arm,coresight-etm3x", "arm,primecell";
...@@ -262,12 +273,14 @@ Example: ...@@ -262,12 +273,14 @@ Example:
cpu = <&cpu1>; cpu = <&cpu1>;
clocks = <&oscclk6a>; clocks = <&oscclk6a>;
clock-names = "apb_pclk"; clock-names = "apb_pclk";
out-ports {
port { port {
ptm1_out_port: endpoint { ptm1_out_port: endpoint {
remote-endpoint = <&funnel_in_port1>; remote-endpoint = <&funnel_in_port1>;
}; };
}; };
}; };
};
4. STM 4. STM
stm@20100000 { stm@20100000 {
...@@ -278,12 +291,14 @@ Example: ...@@ -278,12 +291,14 @@ Example:
clocks = <&soc_smc50mhz>; clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk"; clock-names = "apb_pclk";
out-ports {
port { port {
stm_out_port: endpoint { stm_out_port: endpoint {
remote-endpoint = <&main_funnel_in_port2>; remote-endpoint = <&main_funnel_in_port2>;
}; };
}; };
}; };
};
5. CATU 5. CATU
......
...@@ -45,12 +45,12 @@ of_coresight_get_endpoint_device(struct device_node *endpoint) ...@@ -45,12 +45,12 @@ of_coresight_get_endpoint_device(struct device_node *endpoint)
endpoint, of_dev_node_match); endpoint, of_dev_node_match);
} }
static inline bool of_coresight_ep_is_input(struct device_node *ep) static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep)
{ {
return of_property_read_bool(ep, "slave-mode"); return of_property_read_bool(ep, "slave-mode");
} }
static void of_coresight_get_ports(const struct device_node *node, static void of_coresight_get_ports_legacy(const struct device_node *node,
int *nr_inport, int *nr_outport) int *nr_inport, int *nr_outport)
{ {
struct device_node *ep = NULL; struct device_node *ep = NULL;
...@@ -61,7 +61,7 @@ static void of_coresight_get_ports(const struct device_node *node, ...@@ -61,7 +61,7 @@ static void of_coresight_get_ports(const struct device_node *node,
if (!ep) if (!ep)
break; break;
if (of_coresight_ep_is_input(ep)) if (of_coresight_legacy_ep_is_input(ep))
in++; in++;
else else
out++; out++;
...@@ -72,6 +72,67 @@ static void of_coresight_get_ports(const struct device_node *node, ...@@ -72,6 +72,67 @@ static void of_coresight_get_ports(const struct device_node *node,
*nr_outport = out; *nr_outport = out;
} }
static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
{
struct device_node *parent = of_graph_get_port_parent(ep);
/*
* Skip one-level up to the real device node, if we
* are using the new bindings.
*/
if (!of_node_cmp(parent->name, "in-ports") ||
!of_node_cmp(parent->name, "out-ports"))
parent = of_get_next_parent(parent);
return parent;
}
static inline struct device_node *
of_coresight_get_input_ports_node(const struct device_node *node)
{
return of_get_child_by_name(node, "in-ports");
}
static inline struct device_node *
of_coresight_get_output_ports_node(const struct device_node *node)
{
return of_get_child_by_name(node, "out-ports");
}
static inline int
of_coresight_count_ports(struct device_node *port_parent)
{
int i = 0;
struct device_node *ep = NULL;
while ((ep = of_graph_get_next_endpoint(port_parent, ep)))
i++;
return i;
}
static void of_coresight_get_ports(const struct device_node *node,
int *nr_inport, int *nr_outport)
{
struct device_node *input_ports = NULL, *output_ports = NULL;
input_ports = of_coresight_get_input_ports_node(node);
output_ports = of_coresight_get_output_ports_node(node);
if (input_ports || output_ports) {
if (input_ports) {
*nr_inport = of_coresight_count_ports(input_ports);
of_node_put(input_ports);
}
if (output_ports) {
*nr_outport = of_coresight_count_ports(output_ports);
of_node_put(output_ports);
}
} else {
/* Fall back to legacy DT bindings parsing */
of_coresight_get_ports_legacy(node, nr_inport, nr_outport);
}
}
static int of_coresight_alloc_memory(struct device *dev, static int of_coresight_alloc_memory(struct device *dev,
struct coresight_platform_data *pdata) struct coresight_platform_data *pdata)
{ {
...@@ -136,7 +197,7 @@ static int of_coresight_parse_endpoint(struct device *dev, ...@@ -136,7 +197,7 @@ static int of_coresight_parse_endpoint(struct device *dev,
rep = of_graph_get_remote_endpoint(ep); rep = of_graph_get_remote_endpoint(ep);
if (!rep) if (!rep)
break; break;
rparent = of_graph_get_port_parent(rep); rparent = of_coresight_get_port_parent(rep);
if (!rparent) if (!rparent)
break; break;
if (of_graph_parse_endpoint(rep, &rendpoint)) if (of_graph_parse_endpoint(rep, &rendpoint))
...@@ -176,6 +237,8 @@ of_get_coresight_platform_data(struct device *dev, ...@@ -176,6 +237,8 @@ of_get_coresight_platform_data(struct device *dev,
struct coresight_platform_data *pdata; struct coresight_platform_data *pdata;
struct coresight_connection *conn; struct coresight_connection *conn;
struct device_node *ep = NULL; struct device_node *ep = NULL;
const struct device_node *parent = NULL;
bool legacy_binding = false;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) if (!pdata)
...@@ -196,14 +259,29 @@ of_get_coresight_platform_data(struct device *dev, ...@@ -196,14 +259,29 @@ of_get_coresight_platform_data(struct device *dev,
if (ret) if (ret)
return ERR_PTR(ret); return ERR_PTR(ret);
parent = of_coresight_get_output_ports_node(node);
/*
* If the DT uses obsoleted bindings, the ports are listed
* under the device and we need to filter out the input
* ports.
*/
if (!parent) {
legacy_binding = true;
parent = node;
dev_warn_once(dev, "Uses obsolete Coresight DT bindings\n");
}
conn = pdata->conns; conn = pdata->conns;
/* Iterate through each port to discover topology */
while ((ep = of_graph_get_next_endpoint(node, ep))) { /* Iterate through each output port to discover topology */
while ((ep = of_graph_get_next_endpoint(parent, ep))) {
/* /*
* No need to deal with input ports, as processing the * Legacy binding mixes input/output ports under the
* output ports connected to them will process the details. * same parent. So, skip the input ports if we are dealing
* with legacy binding, as they processed with their
* connected output ports.
*/ */
if (of_coresight_ep_is_input(ep)) if (legacy_binding && of_coresight_legacy_ep_is_input(ep))
continue; continue;
ret = of_coresight_parse_endpoint(dev, ep, conn); ret = of_coresight_parse_endpoint(dev, ep, conn);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment