| // SPDX-License-Identifier: GPL-2.0+ |
| /* |
| * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com> |
| */ |
| |
| #define LOG_CATEGORY LOGC_DT |
| |
| #include <dm.h> |
| #include <log.h> |
| #include <dm/ofnode.h> |
| #include <linux/err.h> |
| |
| /** |
| * ofnode_graph_get_endpoint_count() - get the number of endpoints in a device ofnode |
| * @parent: ofnode to the device containing ports and endpoints |
| * |
| * Return: count of endpoint of this device ofnode |
| */ |
| unsigned int ofnode_graph_get_endpoint_count(ofnode parent) |
| { |
| ofnode ports, port, endpoint; |
| unsigned int num = 0; |
| |
| /* Check if ports node exists */ |
| ports = ofnode_find_subnode(parent, "ports"); |
| if (ofnode_valid(ports)) |
| parent = ports; |
| |
| ofnode_for_each_subnode(port, parent) { |
| if (!strncmp(ofnode_get_name(port), "port", 4)) { |
| /* Port node can only contain endpoints */ |
| ofnode_for_each_subnode(endpoint, port) |
| num++; |
| } |
| }; |
| |
| log_debug("%s: detected %d endpoints\n", __func__, num); |
| |
| return num++; |
| } |
| |
| /** |
| * ofnode_graph_get_port_count() - get the number of port in a device or ports ofnode |
| * @parent: ofnode to the device or ports node |
| * |
| * Return: count of port of this device or ports node |
| */ |
| unsigned int ofnode_graph_get_port_count(ofnode parent) |
| { |
| ofnode ports, port; |
| unsigned int num = 0; |
| |
| /* Check if ports node exists */ |
| ports = ofnode_find_subnode(parent, "ports"); |
| if (ofnode_valid(ports)) |
| parent = ports; |
| |
| ofnode_for_each_subnode(port, parent) |
| if (!strncmp(ofnode_get_name(port), "port", 4)) |
| num++; |
| |
| log_debug("%s: detected %d ports\n", __func__, num); |
| |
| return num++; |
| } |
| |
| /** |
| * ofnode_graph_get_port_by_id() - get the port matching a given id |
| * @parent: parent ofnode |
| * @id: id of the port |
| * |
| * Return: ofnode in given port. |
| */ |
| ofnode ofnode_graph_get_port_by_id(ofnode parent, u32 id) |
| { |
| ofnode ports, port; |
| u32 port_id; |
| |
| ports = ofnode_find_subnode(parent, "ports"); |
| if (!ofnode_valid(ports)) |
| return ofnode_null(); |
| |
| /* Check ports for node with desired id */ |
| ofnode_for_each_subnode(port, ports) { |
| ofnode_read_u32(port, "reg", &port_id); |
| log_debug("%s: detected port %d\n", __func__, port_id); |
| if (port_id == id) |
| return port; |
| } |
| |
| return ofnode_null(); |
| } |
| |
| /** |
| * ofnode_graph_get_endpoint_by_regs() - get the endpoint matching a given id |
| * @parent: parent ofnode |
| * @reg_id: id of the port |
| * @id: id for the endpoint |
| * |
| * Return: ofnode in given endpoint or ofnode_null() if not found. |
| * reg and port_reg are ignored when they are -1. |
| */ |
| ofnode ofnode_graph_get_endpoint_by_regs(ofnode parent, int reg_id, int id) |
| { |
| ofnode port, endpoint; |
| u32 ep_id; |
| |
| /* get the port to work with */ |
| if (reg_id < 0) |
| port = ofnode_find_subnode(parent, "port"); |
| else |
| port = ofnode_graph_get_port_by_id(parent, reg_id); |
| |
| if (!ofnode_valid(port)) { |
| log_debug("%s: port node is not found\n", __func__); |
| return ofnode_null(); |
| } |
| |
| if (id < 0) |
| return ofnode_find_subnode(port, "endpoint"); |
| |
| /* Check endpoints for node with desired id */ |
| ofnode_for_each_subnode(endpoint, port) { |
| ofnode_read_u32(endpoint, "reg", &ep_id); |
| log_debug("%s: detected endpoint %d\n", __func__, ep_id); |
| if (ep_id == id) |
| return endpoint; |
| } |
| |
| return ofnode_null(); |
| } |
| |
| /** |
| * ofnode_graph_get_remote_endpoint() - get remote endpoint node |
| * @endpoint: ofnode of a local endpoint |
| * |
| * Return: Remote endpoint ofnode linked with local endpoint. |
| */ |
| ofnode ofnode_graph_get_remote_endpoint(ofnode endpoint) |
| { |
| /* Get remote endpoint node. */ |
| return ofnode_parse_phandle(endpoint, "remote-endpoint", 0); |
| } |
| |
| /** |
| * ofnode_graph_get_port_parent() - get port's parent node |
| * @endpoint: ofnode of a local endpoint |
| * |
| * Return: device ofnode associated with endpoint |
| */ |
| ofnode ofnode_graph_get_port_parent(ofnode endpoint) |
| { |
| ofnode port = ofnode_get_parent(endpoint); |
| ofnode parent = ofnode_get_parent(port); |
| |
| /* check if we are on top level or in ports node */ |
| if (!strcmp(ofnode_get_name(parent), "ports")) |
| parent = ofnode_get_parent(parent); |
| |
| return parent; |
| } |
| |
| /** |
| * ofnode_graph_get_remote_port_parent() - get remote port's parent ofnode |
| * @endpoint: ofnode of a local endpoint |
| * |
| * Return: device ofnode associated with endpoint linked to local endpoint. |
| */ |
| ofnode ofnode_graph_get_remote_port_parent(ofnode endpoint) |
| { |
| ofnode remote_endpoint = ofnode_graph_get_remote_endpoint(endpoint); |
| if (!ofnode_valid(remote_endpoint)) { |
| log_debug("%s: remote endpoint is not found\n", __func__); |
| return ofnode_null(); |
| } |
| |
| return ofnode_graph_get_port_parent(remote_endpoint); |
| } |
| |
| /** |
| * ofnode_graph_get_remote_port() - get remote port ofnode |
| * @endpoint: ofnode of a local endpoint |
| * |
| * Return: port ofnode associated with remote endpoint node linked |
| * to local endpoint. |
| */ |
| ofnode ofnode_graph_get_remote_port(ofnode endpoint) |
| { |
| ofnode remote_endpoint = ofnode_graph_get_remote_endpoint(endpoint); |
| if (!ofnode_valid(remote_endpoint)) { |
| log_debug("%s: remote endpoint is not found\n", __func__); |
| return ofnode_null(); |
| } |
| |
| return ofnode_get_parent(remote_endpoint); |
| } |
| |
| /** |
| * ofnode_graph_get_remote_node() - get remote parent ofnode for given port/endpoint |
| * @parent: parent ofnode containing graph port/endpoint |
| * @port: identifier (value of reg property) of the parent port ofnode |
| * @endpoint: identifier (value of reg property) of the endpoint ofnode |
| * |
| * Return: device ofnode associated with endpoint linked to local endpoint. |
| */ |
| ofnode ofnode_graph_get_remote_node(ofnode parent, int port, int endpoint) |
| { |
| ofnode endpoint_ofnode; |
| |
| endpoint_ofnode = ofnode_graph_get_endpoint_by_regs(parent, port, endpoint); |
| if (!ofnode_valid(endpoint_ofnode)) { |
| log_debug("%s: endpoint is not found\n", __func__); |
| return ofnode_null(); |
| } |
| |
| return ofnode_graph_get_remote_port_parent(endpoint_ofnode); |
| } |