Svyatoslav Ryhel | 2e23746 | 2025-02-15 19:46:29 +0200 | [diff] [blame] | 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 | */ |
| 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 | */ |
| 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 | */ |
| 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 and port_reg are ignored when they are -1. |
| 102 | */ |
| 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 | */ |
| 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 | */ |
| 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 | */ |
| 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 | */ |
| 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 | */ |
| 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 | } |