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