19a4eed0bSEmmanuel Vadot /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 39a4eed0bSEmmanuel Vadot * 49a4eed0bSEmmanuel Vadot * Copyright (c) 2019 Emmanuel Vadot <manu@FreeBSD.org> 59a4eed0bSEmmanuel Vadot * 69a4eed0bSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 79a4eed0bSEmmanuel Vadot * modification, are permitted provided that the following conditions 89a4eed0bSEmmanuel Vadot * are met: 99a4eed0bSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 109a4eed0bSEmmanuel Vadot * notice, this list of conditions, and the following disclaimer, 119a4eed0bSEmmanuel Vadot * without modification, immediately at the beginning of the file. 129a4eed0bSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 139a4eed0bSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in 149a4eed0bSEmmanuel Vadot * the documentation and/or other materials provided with the 159a4eed0bSEmmanuel Vadot * distribution. 169a4eed0bSEmmanuel Vadot * 179a4eed0bSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 189a4eed0bSEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 199a4eed0bSEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 209a4eed0bSEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 219a4eed0bSEmmanuel Vadot * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 229a4eed0bSEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 239a4eed0bSEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 249a4eed0bSEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 259a4eed0bSEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 269a4eed0bSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 279a4eed0bSEmmanuel Vadot * SUCH DAMAGE. 289a4eed0bSEmmanuel Vadot * 299a4eed0bSEmmanuel Vadot * $FreeBSD$ 309a4eed0bSEmmanuel Vadot */ 319a4eed0bSEmmanuel Vadot 329a4eed0bSEmmanuel Vadot #include <sys/cdefs.h> 339a4eed0bSEmmanuel Vadot __FBSDID("$FreeBSD$"); 349a4eed0bSEmmanuel Vadot 359a4eed0bSEmmanuel Vadot #include "opt_platform.h" 369a4eed0bSEmmanuel Vadot #include <sys/param.h> 379a4eed0bSEmmanuel Vadot #include <sys/systm.h> 389a4eed0bSEmmanuel Vadot #include <sys/bus.h> 399a4eed0bSEmmanuel Vadot #include <sys/errno.h> 409a4eed0bSEmmanuel Vadot 419a4eed0bSEmmanuel Vadot #include <dev/ofw/ofw_bus.h> 429a4eed0bSEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h> 439a4eed0bSEmmanuel Vadot #include <dev/ofw/ofw_graph.h> 449a4eed0bSEmmanuel Vadot #include <dev/ofw/openfirm.h> 459a4eed0bSEmmanuel Vadot 469a4eed0bSEmmanuel Vadot #include "ofw_bus_if.h" 479a4eed0bSEmmanuel Vadot 489a4eed0bSEmmanuel Vadot #define PORT_MAX_NAME 8 499a4eed0bSEmmanuel Vadot 509a4eed0bSEmmanuel Vadot phandle_t 519a4eed0bSEmmanuel Vadot ofw_graph_get_port_by_idx(phandle_t node, uint32_t idx) 529a4eed0bSEmmanuel Vadot { 539a4eed0bSEmmanuel Vadot phandle_t ports, child; 549a4eed0bSEmmanuel Vadot uint32_t reg; 559a4eed0bSEmmanuel Vadot char portnode[PORT_MAX_NAME]; 569a4eed0bSEmmanuel Vadot 579a4eed0bSEmmanuel Vadot /* First try to find a port@<idx> node */ 589a4eed0bSEmmanuel Vadot snprintf(portnode, sizeof(portnode), "port@%d", idx); 599a4eed0bSEmmanuel Vadot child = ofw_bus_find_child(node, portnode); 609a4eed0bSEmmanuel Vadot if (child != 0) 619a4eed0bSEmmanuel Vadot return (child); 629a4eed0bSEmmanuel Vadot 639146c624SRuslan Bukin /* Now check for 'port' without explicit index. */ 649146c624SRuslan Bukin if (idx == 0) { 659146c624SRuslan Bukin snprintf(portnode, sizeof(portnode), "port"); 669146c624SRuslan Bukin child = ofw_bus_find_child(node, portnode); 679146c624SRuslan Bukin if (child != 0) 689146c624SRuslan Bukin return (child); 699146c624SRuslan Bukin } 709146c624SRuslan Bukin 719a4eed0bSEmmanuel Vadot /* Next try to look under ports */ 729a4eed0bSEmmanuel Vadot ports = ofw_bus_find_child(node, "ports"); 739a4eed0bSEmmanuel Vadot if (ports == 0) 749a4eed0bSEmmanuel Vadot return (0); 759a4eed0bSEmmanuel Vadot 769a4eed0bSEmmanuel Vadot for (child = OF_child(ports); child != 0; child = OF_peer(child)) { 779a4eed0bSEmmanuel Vadot if (OF_getencprop(child, "reg", ®, sizeof(uint32_t)) <= 0 || 789a4eed0bSEmmanuel Vadot reg != idx) 799a4eed0bSEmmanuel Vadot continue; 809a4eed0bSEmmanuel Vadot 819a4eed0bSEmmanuel Vadot return (child); 829a4eed0bSEmmanuel Vadot } 839a4eed0bSEmmanuel Vadot 849a4eed0bSEmmanuel Vadot return (0); 859a4eed0bSEmmanuel Vadot } 869a4eed0bSEmmanuel Vadot 879a4eed0bSEmmanuel Vadot size_t 889a4eed0bSEmmanuel Vadot ofw_graph_port_get_num_endpoints(phandle_t port) 899a4eed0bSEmmanuel Vadot { 909a4eed0bSEmmanuel Vadot phandle_t child; 919a4eed0bSEmmanuel Vadot char *name; 929a4eed0bSEmmanuel Vadot size_t num = 0; 939a4eed0bSEmmanuel Vadot int ret; 949a4eed0bSEmmanuel Vadot 959a4eed0bSEmmanuel Vadot for (num = 0, child = OF_child(port); child != 0; 969a4eed0bSEmmanuel Vadot child = OF_peer(child)) { 979a4eed0bSEmmanuel Vadot ret = OF_getprop_alloc(child, "name", (void **)&name); 989a4eed0bSEmmanuel Vadot if (ret == -1) 999a4eed0bSEmmanuel Vadot continue; 1009a4eed0bSEmmanuel Vadot if (strcmp(name, "endpoint") == 0) 1019a4eed0bSEmmanuel Vadot num++; 1029a4eed0bSEmmanuel Vadot else if (strncmp(name, "endpoint@", 9) == 0) 1039a4eed0bSEmmanuel Vadot num++; 1049a4eed0bSEmmanuel Vadot free(name, M_OFWPROP); 1059a4eed0bSEmmanuel Vadot } 1069a4eed0bSEmmanuel Vadot 1079a4eed0bSEmmanuel Vadot return (num); 1089a4eed0bSEmmanuel Vadot } 1099a4eed0bSEmmanuel Vadot 1109a4eed0bSEmmanuel Vadot phandle_t 1119a4eed0bSEmmanuel Vadot ofw_graph_get_endpoint_by_idx(phandle_t port, uint32_t idx) 1129a4eed0bSEmmanuel Vadot { 1139a4eed0bSEmmanuel Vadot phandle_t endpoint, child; 1149a4eed0bSEmmanuel Vadot uint32_t reg; 1159a4eed0bSEmmanuel Vadot 1169a4eed0bSEmmanuel Vadot /* First test if we have only one endpoint */ 1179a4eed0bSEmmanuel Vadot endpoint = ofw_bus_find_child(port, "endpoint"); 1189a4eed0bSEmmanuel Vadot if (endpoint != 0) 1199a4eed0bSEmmanuel Vadot return (endpoint); 1209a4eed0bSEmmanuel Vadot 1219a4eed0bSEmmanuel Vadot /* Then test all childs based on the reg property */ 1229a4eed0bSEmmanuel Vadot for (child = OF_child(port); child != 0; child = OF_peer(child)) { 1239a4eed0bSEmmanuel Vadot if (OF_getencprop(child, "reg", ®, sizeof(uint32_t)) <= 0 || 1249a4eed0bSEmmanuel Vadot reg != idx) 1259a4eed0bSEmmanuel Vadot continue; 1269a4eed0bSEmmanuel Vadot 1279a4eed0bSEmmanuel Vadot return (child); 1289a4eed0bSEmmanuel Vadot } 1299a4eed0bSEmmanuel Vadot 1309a4eed0bSEmmanuel Vadot return (0); 1319a4eed0bSEmmanuel Vadot } 1329a4eed0bSEmmanuel Vadot 1339a4eed0bSEmmanuel Vadot phandle_t 1349a4eed0bSEmmanuel Vadot ofw_graph_get_remote_endpoint(phandle_t endpoint) 1359a4eed0bSEmmanuel Vadot { 1369a4eed0bSEmmanuel Vadot phandle_t remote; 1379a4eed0bSEmmanuel Vadot 1389a4eed0bSEmmanuel Vadot if (OF_getencprop(endpoint, "remote-endpoint", &remote, 1399a4eed0bSEmmanuel Vadot sizeof(phandle_t)) <= 0) 1409a4eed0bSEmmanuel Vadot return (0); 1419a4eed0bSEmmanuel Vadot 1429a4eed0bSEmmanuel Vadot return (remote); 1439a4eed0bSEmmanuel Vadot } 1449a4eed0bSEmmanuel Vadot 1459a4eed0bSEmmanuel Vadot phandle_t 1469a4eed0bSEmmanuel Vadot ofw_graph_get_remote_parent(phandle_t remote) 1479a4eed0bSEmmanuel Vadot { 1489a4eed0bSEmmanuel Vadot phandle_t node; 1499a4eed0bSEmmanuel Vadot char *name; 1509a4eed0bSEmmanuel Vadot int ret; 1519a4eed0bSEmmanuel Vadot 1529a4eed0bSEmmanuel Vadot /* get the endpoint node */ 1539a4eed0bSEmmanuel Vadot node = OF_node_from_xref(remote); 1549a4eed0bSEmmanuel Vadot 1559a4eed0bSEmmanuel Vadot /* go to the port@X node */ 1569a4eed0bSEmmanuel Vadot node = OF_parent(node); 1579a4eed0bSEmmanuel Vadot /* go to the ports node or parent */ 1589a4eed0bSEmmanuel Vadot node = OF_parent(node); 1599a4eed0bSEmmanuel Vadot 1609a4eed0bSEmmanuel Vadot /* if the node name is 'ports' we need to go up one last time */ 1619a4eed0bSEmmanuel Vadot ret = OF_getprop_alloc(node, "name", (void **)&name); 1629a4eed0bSEmmanuel Vadot if (ret == -1) { 1639a4eed0bSEmmanuel Vadot printf("%s: Node %x don't have a name, abort\n", __func__, node); 1649a4eed0bSEmmanuel Vadot node = 0; 1659a4eed0bSEmmanuel Vadot goto end; 1669a4eed0bSEmmanuel Vadot } 1679a4eed0bSEmmanuel Vadot if (strcmp("ports", name) == 0) 1689a4eed0bSEmmanuel Vadot node = OF_parent(node); 1699a4eed0bSEmmanuel Vadot 1709a4eed0bSEmmanuel Vadot end: 1719a4eed0bSEmmanuel Vadot free(name, M_OFWPROP); 1729a4eed0bSEmmanuel Vadot return (node); 1739a4eed0bSEmmanuel Vadot } 1749a4eed0bSEmmanuel Vadot 1759a4eed0bSEmmanuel Vadot device_t 1769a4eed0bSEmmanuel Vadot ofw_graph_get_device_by_port_ep(phandle_t node, uint32_t port_id, uint32_t ep_id) 1779a4eed0bSEmmanuel Vadot { 1789a4eed0bSEmmanuel Vadot phandle_t outport, port, endpoint, remote; 1799a4eed0bSEmmanuel Vadot 1809a4eed0bSEmmanuel Vadot port = ofw_graph_get_port_by_idx(node, port_id); 1819a4eed0bSEmmanuel Vadot if (port == 0) 1829a4eed0bSEmmanuel Vadot return (NULL); 1839a4eed0bSEmmanuel Vadot endpoint = ofw_graph_get_endpoint_by_idx(port, ep_id); 1849a4eed0bSEmmanuel Vadot if (endpoint == 0) 1859a4eed0bSEmmanuel Vadot return NULL; 1869a4eed0bSEmmanuel Vadot remote = ofw_graph_get_remote_endpoint(endpoint); 1879a4eed0bSEmmanuel Vadot if (remote == 0) 1889a4eed0bSEmmanuel Vadot return (NULL); 1899a4eed0bSEmmanuel Vadot outport = ofw_graph_get_remote_parent(remote); 1909a4eed0bSEmmanuel Vadot if (outport == 0) 1919a4eed0bSEmmanuel Vadot return (NULL); 1929a4eed0bSEmmanuel Vadot 1939a4eed0bSEmmanuel Vadot return (OF_device_from_xref(OF_xref_from_node(outport))); 1949a4eed0bSEmmanuel Vadot } 195