1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
4  */
5 
6 #define LOG_CATEGORY	LOGC_DT
7 
8 #include <dm.h>
9 #include <log.h>
10 #include <dm/ofnode.h>
11 #include <linux/err.h>
12 
13 /**
14  * ofnode_graph_get_endpoint_count() - get the number of endpoints in a device ofnode
15  * @parent: ofnode to the device containing ports and endpoints
16  *
17  * Return: count of endpoint of this device ofnode
18  */
ofnode_graph_get_endpoint_count(ofnode parent)19 unsigned int ofnode_graph_get_endpoint_count(ofnode parent)
20 {
21 	ofnode ports, port, endpoint;
22 	unsigned int num = 0;
23 
24 	/* Check if ports node exists */
25 	ports = ofnode_find_subnode(parent, "ports");
26 	if (ofnode_valid(ports))
27 		parent = ports;
28 
29 	ofnode_for_each_subnode(port, parent) {
30 		if (!strncmp(ofnode_get_name(port), "port", 4)) {
31 			/* Port node can only contain endpoints */
32 			ofnode_for_each_subnode(endpoint, port)
33 				num++;
34 		}
35 	};
36 
37 	log_debug("%s: detected %d endpoints\n", __func__, num);
38 
39 	return num++;
40 }
41 
42 /**
43  * ofnode_graph_get_port_count() - get the number of port in a device or ports ofnode
44  * @parent: ofnode to the device or ports node
45  *
46  * Return: count of port of this device or ports node
47  */
ofnode_graph_get_port_count(ofnode parent)48 unsigned int ofnode_graph_get_port_count(ofnode parent)
49 {
50 	ofnode ports, port;
51 	unsigned int num = 0;
52 
53 	/* Check if ports node exists */
54 	ports = ofnode_find_subnode(parent, "ports");
55 	if (ofnode_valid(ports))
56 		parent = ports;
57 
58 	ofnode_for_each_subnode(port, parent)
59 		if (!strncmp(ofnode_get_name(port), "port", 4))
60 			num++;
61 
62 	log_debug("%s: detected %d ports\n", __func__, num);
63 
64 	return num++;
65 }
66 
67 /**
68  * ofnode_graph_get_port_by_id() - get the port matching a given id
69  * @parent: parent ofnode
70  * @id: id of the port
71  *
72  * Return: ofnode in given port.
73  */
ofnode_graph_get_port_by_id(ofnode parent,u32 id)74 ofnode ofnode_graph_get_port_by_id(ofnode parent, u32 id)
75 {
76 	ofnode ports, port;
77 	u32 port_id;
78 
79 	ports = ofnode_find_subnode(parent, "ports");
80 	if (!ofnode_valid(ports))
81 		return ofnode_null();
82 
83 	/* Check ports for node with desired id */
84 	ofnode_for_each_subnode(port, ports) {
85 		ofnode_read_u32(port, "reg", &port_id);
86 		log_debug("%s: detected port %d\n", __func__, port_id);
87 		if (port_id == id)
88 			return port;
89 	}
90 
91 	return ofnode_null();
92 }
93 
94 /**
95  * ofnode_graph_get_endpoint_by_regs() - get the endpoint matching a given id
96  * @parent: parent ofnode
97  * @reg_id: id of the port
98  * @id: id for the endpoint
99  *
100  * Return: ofnode in given endpoint or ofnode_null() if not found.
101  * reg_id and id are ignored when they are -1.
102  */
ofnode_graph_get_endpoint_by_regs(ofnode parent,int reg_id,int id)103 ofnode ofnode_graph_get_endpoint_by_regs(ofnode parent, int reg_id, int id)
104 {
105 	ofnode port, endpoint;
106 	u32 ep_id;
107 
108 	/* get the port to work with */
109 	if (reg_id < 0)
110 		port = ofnode_find_subnode(parent, "port");
111 	else
112 		port = ofnode_graph_get_port_by_id(parent, reg_id);
113 
114 	if (!ofnode_valid(port)) {
115 		log_debug("%s: port node is not found\n", __func__);
116 		return ofnode_null();
117 	}
118 
119 	if (id < 0)
120 		return ofnode_find_subnode(port, "endpoint");
121 
122 	/* Check endpoints for node with desired id */
123 	ofnode_for_each_subnode(endpoint, port) {
124 		ofnode_read_u32(endpoint, "reg", &ep_id);
125 		log_debug("%s: detected endpoint %d\n", __func__, ep_id);
126 		if (ep_id == id)
127 			return endpoint;
128 	}
129 
130 	return ofnode_null();
131 }
132 
133 /**
134  * ofnode_graph_get_remote_endpoint() - get remote endpoint node
135  * @endpoint: ofnode of a local endpoint
136  *
137  * Return: Remote endpoint ofnode linked with local endpoint.
138  */
ofnode_graph_get_remote_endpoint(ofnode endpoint)139 ofnode ofnode_graph_get_remote_endpoint(ofnode endpoint)
140 {
141 	/* Get remote endpoint node. */
142 	return ofnode_parse_phandle(endpoint, "remote-endpoint", 0);
143 }
144 
145 /**
146  * ofnode_graph_get_port_parent() - get port's parent node
147  * @endpoint: ofnode of a local endpoint
148  *
149  * Return: device ofnode associated with endpoint
150  */
ofnode_graph_get_port_parent(ofnode endpoint)151 ofnode ofnode_graph_get_port_parent(ofnode endpoint)
152 {
153 	ofnode port = ofnode_get_parent(endpoint);
154 	ofnode parent = ofnode_get_parent(port);
155 
156 	/* check if we are on top level or in ports node */
157 	if (!strcmp(ofnode_get_name(parent), "ports"))
158 		parent = ofnode_get_parent(parent);
159 
160 	return parent;
161 }
162 
163 /**
164  * ofnode_graph_get_remote_port_parent() - get remote port's parent ofnode
165  * @endpoint: ofnode of a local endpoint
166  *
167  * Return: device ofnode associated with endpoint linked to local endpoint.
168  */
ofnode_graph_get_remote_port_parent(ofnode endpoint)169 ofnode ofnode_graph_get_remote_port_parent(ofnode endpoint)
170 {
171 	ofnode remote_endpoint = ofnode_graph_get_remote_endpoint(endpoint);
172 	if (!ofnode_valid(remote_endpoint)) {
173 		log_debug("%s: remote endpoint is not found\n", __func__);
174 		return ofnode_null();
175 	}
176 
177 	return ofnode_graph_get_port_parent(remote_endpoint);
178 }
179 
180 /**
181  * ofnode_graph_get_remote_port() - get remote port ofnode
182  * @endpoint: ofnode of a local endpoint
183  *
184  * Return: port ofnode associated with remote endpoint node linked
185  * to local endpoint.
186  */
ofnode_graph_get_remote_port(ofnode endpoint)187 ofnode ofnode_graph_get_remote_port(ofnode endpoint)
188 {
189 	ofnode remote_endpoint = ofnode_graph_get_remote_endpoint(endpoint);
190 	if (!ofnode_valid(remote_endpoint)) {
191 		log_debug("%s: remote endpoint is not found\n", __func__);
192 		return ofnode_null();
193 	}
194 
195 	return ofnode_get_parent(remote_endpoint);
196 }
197 
198 /**
199  * ofnode_graph_get_remote_node() - get remote parent ofnode for given port/endpoint
200  * @parent: parent ofnode containing graph port/endpoint
201  * @port: identifier (value of reg property) of the parent port ofnode
202  * @endpoint: identifier (value of reg property) of the endpoint ofnode
203  *
204  * Return: device ofnode associated with endpoint linked to local endpoint.
205  */
ofnode_graph_get_remote_node(ofnode parent,int port,int endpoint)206 ofnode ofnode_graph_get_remote_node(ofnode parent, int port, int endpoint)
207 {
208 	ofnode endpoint_ofnode;
209 
210 	endpoint_ofnode = ofnode_graph_get_endpoint_by_regs(parent, port, endpoint);
211 	if (!ofnode_valid(endpoint_ofnode)) {
212 		log_debug("%s: endpoint is not found\n", __func__);
213 		return ofnode_null();
214 	}
215 
216 	return ofnode_graph_get_remote_port_parent(endpoint_ofnode);
217 }
218