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(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
 104struct coresight_platform_data *of_get_coresight_platform_data(
 105                                struct device *dev, struct device_node *node)
 106{
 107        int i = 0, ret = 0, cpu;
 108        struct coresight_platform_data *pdata;
 109        struct of_endpoint endpoint, rendpoint;
 110        struct device *rdev;
 111        struct device_node *dn;
 112        struct device_node *ep = NULL;
 113        struct device_node *rparent = NULL;
 114        struct device_node *rport = NULL;
 115
 116        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 117        if (!pdata)
 118                return ERR_PTR(-ENOMEM);
 119
 120        /* Use device name as sysfs handle */
 121        pdata->name = dev_name(dev);
 122
 123        /* Get the number of input and output port for this component */
 124        of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport);
 125
 126        if (pdata->nr_outport) {
 127                ret = of_coresight_alloc_memory(dev, pdata);
 128                if (ret)
 129                        return ERR_PTR(ret);
 130
 131                /* Iterate through each port to discover topology */
 132                do {
 133                        /* Get a handle on a port */
 134                        ep = of_graph_get_next_endpoint(node, ep);
 135                        if (!ep)
 136                                break;
 137
 138                        /*
 139                         * No need to deal with input ports, processing for as
 140                         * processing for output ports will deal with them.
 141                         */
 142                        if (of_find_property(ep, "slave-mode", NULL))
 143                                continue;
 144
 145                        /* Get a handle on the local endpoint */
 146                        ret = of_graph_parse_endpoint(ep, &endpoint);
 147
 148                        if (ret)
 149                                continue;
 150
 151                        /* The local out port number */
 152                        pdata->outports[i] = endpoint.id;
 153
 154                        /*
 155                         * Get a handle on the remote port and parent
 156                         * attached to it.
 157                         */
 158                        rparent = of_graph_get_remote_port_parent(ep);
 159                        rport = of_graph_get_remote_port(ep);
 160
 161                        if (!rparent || !rport)
 162                                continue;
 163
 164                        if (of_graph_parse_endpoint(rport, &rendpoint))
 165                                continue;
 166
 167                        rdev = of_coresight_get_endpoint_device(rparent);
 168                        if (!rdev)
 169                                continue;
 170
 171                        pdata->child_names[i] = dev_name(rdev);
 172                        pdata->child_ports[i] = rendpoint.id;
 173
 174                        i++;
 175                } while (ep);
 176        }
 177
 178        /* Affinity defaults to CPU0 */
 179        pdata->cpu = 0;
 180        dn = of_parse_phandle(node, "cpu", 0);
 181        for (cpu = 0; dn && cpu < nr_cpu_ids; cpu++) {
 182                if (dn == of_get_cpu_node(cpu, NULL)) {
 183                        pdata->cpu = cpu;
 184                        break;
 185                }
 186        }
 187
 188        return pdata;
 189}
 190EXPORT_SYMBOL_GPL(of_get_coresight_platform_data);
 191