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