linux/drivers/hwtracing/coresight/of_coresight.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2012, The Linux Foundation. All rights reserved.
   4 */
   5
   6#include <linux/types.h>
   7#include <linux/err.h>
   8#include <linux/slab.h>
   9#include <linux/clk.h>
  10#include <linux/of.h>
  11#include <linux/of_address.h>
  12#include <linux/of_graph.h>
  13#include <linux/of_platform.h>
  14#include <linux/platform_device.h>
  15#include <linux/amba/bus.h>
  16#include <linux/coresight.h>
  17#include <linux/cpumask.h>
  18#include <asm/smp_plat.h>
  19
  20
  21static int of_dev_node_match(struct device *dev, void *data)
  22{
  23        return dev->of_node == data;
  24}
  25
  26static struct device *
  27of_coresight_get_endpoint_device(struct device_node *endpoint)
  28{
  29        struct device *dev = NULL;
  30
  31        /*
  32         * If we have a non-configurable replicator, it will be found on the
  33         * platform bus.
  34         */
  35        dev = bus_find_device(&platform_bus_type, NULL,
  36                              endpoint, of_dev_node_match);
  37        if (dev)
  38                return dev;
  39
  40        /*
  41         * We have a configurable component - circle through the AMBA bus
  42         * looking for the device that matches the endpoint node.
  43         */
  44        return bus_find_device(&amba_bustype, NULL,
  45                               endpoint, of_dev_node_match);
  46}
  47
  48static void of_coresight_get_ports(const struct device_node *node,
  49                                   int *nr_inport, int *nr_outport)
  50{
  51        struct device_node *ep = NULL;
  52        int in = 0, out = 0;
  53
  54        do {
  55                ep = of_graph_get_next_endpoint(node, ep);
  56                if (!ep)
  57                        break;
  58
  59                if (of_property_read_bool(ep, "slave-mode"))
  60                        in++;
  61                else
  62                        out++;
  63
  64        } while (ep);
  65
  66        *nr_inport = in;
  67        *nr_outport = out;
  68}
  69
  70static int of_coresight_alloc_memory(struct device *dev,
  71                        struct coresight_platform_data *pdata)
  72{
  73        /* List of output port on this component */
  74        pdata->outports = devm_kcalloc(dev,
  75                                       pdata->nr_outport,
  76                                       sizeof(*pdata->outports),
  77                                       GFP_KERNEL);
  78        if (!pdata->outports)
  79                return -ENOMEM;
  80
  81        /* Children connected to this component via @outports */
  82        pdata->child_names = devm_kcalloc(dev,
  83                                          pdata->nr_outport,
  84                                          sizeof(*pdata->child_names),
  85                                          GFP_KERNEL);
  86        if (!pdata->child_names)
  87                return -ENOMEM;
  88
  89        /* Port number on the child this component is connected to */
  90        pdata->child_ports = devm_kcalloc(dev,
  91                                          pdata->nr_outport,
  92                                          sizeof(*pdata->child_ports),
  93                                          GFP_KERNEL);
  94        if (!pdata->child_ports)
  95                return -ENOMEM;
  96
  97        return 0;
  98}
  99
 100int of_coresight_get_cpu(const struct device_node *node)
 101{
 102        int cpu;
 103        struct device_node *dn;
 104
 105        dn = of_parse_phandle(node, "cpu", 0);
 106        /* Affinity defaults to CPU0 */
 107        if (!dn)
 108                return 0;
 109        cpu = of_cpu_node_to_id(dn);
 110        of_node_put(dn);
 111
 112        /* Affinity to CPU0 if no cpu nodes are found */
 113        return (cpu < 0) ? 0 : cpu;
 114}
 115EXPORT_SYMBOL_GPL(of_coresight_get_cpu);
 116
 117struct coresight_platform_data *
 118of_get_coresight_platform_data(struct device *dev,
 119                               const struct device_node *node)
 120{
 121        int i = 0, ret = 0;
 122        struct coresight_platform_data *pdata;
 123        struct of_endpoint endpoint, rendpoint;
 124        struct device *rdev;
 125        struct device_node *ep = NULL;
 126        struct device_node *rparent = NULL;
 127        struct device_node *rport = NULL;
 128
 129        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 130        if (!pdata)
 131                return ERR_PTR(-ENOMEM);
 132
 133        /* Use device name as sysfs handle */
 134        pdata->name = dev_name(dev);
 135
 136        /* Get the number of input and output port for this component */
 137        of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport);
 138
 139        if (pdata->nr_outport) {
 140                ret = of_coresight_alloc_memory(dev, pdata);
 141                if (ret)
 142                        return ERR_PTR(ret);
 143
 144                /* Iterate through each port to discover topology */
 145                do {
 146                        /* Get a handle on a port */
 147                        ep = of_graph_get_next_endpoint(node, ep);
 148                        if (!ep)
 149                                break;
 150
 151                        /*
 152                         * No need to deal with input ports, processing for as
 153                         * processing for output ports will deal with them.
 154                         */
 155                        if (of_find_property(ep, "slave-mode", NULL))
 156                                continue;
 157
 158                        /* Get a handle on the local endpoint */
 159                        ret = of_graph_parse_endpoint(ep, &endpoint);
 160
 161                        if (ret)
 162                                continue;
 163
 164                        /* The local out port number */
 165                        pdata->outports[i] = endpoint.port;
 166
 167                        /*
 168                         * Get a handle on the remote port and parent
 169                         * attached to it.
 170                         */
 171                        rparent = of_graph_get_remote_port_parent(ep);
 172                        rport = of_graph_get_remote_port(ep);
 173
 174                        if (!rparent || !rport)
 175                                continue;
 176
 177                        if (of_graph_parse_endpoint(rport, &rendpoint))
 178                                continue;
 179
 180                        rdev = of_coresight_get_endpoint_device(rparent);
 181                        if (!rdev)
 182                                return ERR_PTR(-EPROBE_DEFER);
 183
 184                        pdata->child_names[i] = dev_name(rdev);
 185                        pdata->child_ports[i] = rendpoint.id;
 186
 187                        i++;
 188                } while (ep);
 189        }
 190
 191        pdata->cpu = of_coresight_get_cpu(node);
 192
 193        return pdata;
 194}
 195EXPORT_SYMBOL_GPL(of_get_coresight_platform_data);
 196