diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index 5d1ad09bafb4..f39d2c6eb49c 100644 --- a/Documentation/devicetree/bindings/arm/coresight.txt +++ b/Documentation/devicetree/bindings/arm/coresight.txt @@ -54,9 +54,7 @@ its hardware characteristcs. clocks the core of that coresight component. The latter clock is optional. - * port or ports: The representation of the component's port - layout using the generic DT graph presentation found in - "bindings/graph.txt". + * port or ports: see "Graph bindings for Coresight" below. * Additional required properties for System Trace Macrocells (STM): * reg: along with the physical base address and length of the register @@ -73,7 +71,7 @@ its hardware characteristcs. AMBA markee): - "arm,coresight-replicator" - * port or ports: same as above. + * port or ports: see "Graph bindings for Coresight" below. * Optional properties for ETM/PTMs: @@ -96,6 +94,20 @@ its hardware characteristcs. * interrupts : Exactly one SPI may be listed for reporting the address 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: 1. Sinks @@ -105,10 +117,11 @@ Example: clocks = <&oscclk6a>; clock-names = "apb_pclk"; - port { - etb_in_port: endpoint@0 { - slave-mode; - remote-endpoint = <&replicator_out_port0>; + in-ports { + port { + etb_in_port: endpoint@0 { + remote-endpoint = <&replicator_out_port0>; + }; }; }; }; @@ -119,10 +132,11 @@ Example: clocks = <&oscclk6a>; clock-names = "apb_pclk"; - port { - tpiu_in_port: endpoint@0 { - slave-mode; - remote-endpoint = <&replicator_out_port1>; + out-ports { + port { + tpiu_in_port: endpoint@0 { + remote-endpoint = <&replicator_out_port1>; + }; }; }; }; @@ -163,7 +177,7 @@ Example: */ compatible = "arm,coresight-replicator"; - ports { + out-ports { #address-cells = <1>; #size-cells = <0>; @@ -181,12 +195,11 @@ Example: remote-endpoint = <&tpiu_in_port>; }; }; + }; - /* replicator input port */ - port@2 { - reg = <0>; + in-ports { + port { replicator_in_port0: endpoint { - slave-mode; remote-endpoint = <&funnel_out_port0>; }; }; @@ -199,40 +212,36 @@ Example: clocks = <&oscclk6a>; clock-names = "apb_pclk"; - ports { - #address-cells = <1>; - #size-cells = <0>; - - /* funnel output port */ - port@0 { - reg = <0>; + out-ports { + port { funnel_out_port0: endpoint { remote-endpoint = <&replicator_in_port0>; }; }; + }; - /* funnel input ports */ - port@1 { + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { reg = <0>; funnel_in_port0: endpoint { - slave-mode; remote-endpoint = <&ptm0_out_port>; }; }; - port@2 { + port@1 { reg = <1>; funnel_in_port1: endpoint { - slave-mode; remote-endpoint = <&ptm1_out_port>; }; }; - port@3 { + port@2 { reg = <2>; funnel_in_port2: endpoint { - slave-mode; remote-endpoint = <&etm0_out_port>; }; }; @@ -248,9 +257,11 @@ Example: cpu = <&cpu0>; clocks = <&oscclk6a>; clock-names = "apb_pclk"; - port { - ptm0_out_port: endpoint { - remote-endpoint = <&funnel_in_port0>; + out-ports { + port { + ptm0_out_port: endpoint { + remote-endpoint = <&funnel_in_port0>; + }; }; }; }; @@ -262,9 +273,11 @@ Example: cpu = <&cpu1>; clocks = <&oscclk6a>; clock-names = "apb_pclk"; - port { - ptm1_out_port: endpoint { - remote-endpoint = <&funnel_in_port1>; + out-ports { + port { + ptm1_out_port: endpoint { + remote-endpoint = <&funnel_in_port1>; + }; }; }; }; @@ -278,9 +291,11 @@ Example: clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - port { - stm_out_port: endpoint { - remote-endpoint = <&main_funnel_in_port2>; + out-ports { + port { + stm_out_port: endpoint { + remote-endpoint = <&main_funnel_in_port2>; + }; }; }; }; diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c index e8fb4e124744..da71c975e3f7 100644 --- a/drivers/hwtracing/coresight/of_coresight.c +++ b/drivers/hwtracing/coresight/of_coresight.c @@ -45,13 +45,13 @@ of_coresight_get_endpoint_device(struct device_node *endpoint) 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"); } -static void of_coresight_get_ports(const struct device_node *node, - int *nr_inport, int *nr_outport) +static void of_coresight_get_ports_legacy(const struct device_node *node, + int *nr_inport, int *nr_outport) { struct device_node *ep = NULL; int in = 0, out = 0; @@ -61,7 +61,7 @@ static void of_coresight_get_ports(const struct device_node *node, if (!ep) break; - if (of_coresight_ep_is_input(ep)) + if (of_coresight_legacy_ep_is_input(ep)) in++; else out++; @@ -72,6 +72,67 @@ static void of_coresight_get_ports(const struct device_node *node, *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, struct coresight_platform_data *pdata) { @@ -136,7 +197,7 @@ static int of_coresight_parse_endpoint(struct device *dev, rep = of_graph_get_remote_endpoint(ep); if (!rep) break; - rparent = of_graph_get_port_parent(rep); + rparent = of_coresight_get_port_parent(rep); if (!rparent) break; if (of_graph_parse_endpoint(rep, &rendpoint)) @@ -176,6 +237,8 @@ of_get_coresight_platform_data(struct device *dev, struct coresight_platform_data *pdata; struct coresight_connection *conn; struct device_node *ep = NULL; + const struct device_node *parent = NULL; + bool legacy_binding = false; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -196,14 +259,29 @@ of_get_coresight_platform_data(struct device *dev, if (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; - /* 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 - * output ports connected to them will process the details. + * Legacy binding mixes input/output ports under the + * 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; ret = of_coresight_parse_endpoint(dev, ep, conn);